vue-cli
用 vue-cli 直接生成一个 vue 项目很简单方便,不过要想深入学习并掌控 vue 项目,了解项目是如何建构的是很必要,今天就来一边学习一边试着分析。
本文 vue-cli 版本 2.9.6
一、初始化目录结构
vue 主要文件目录:
- build (构建项目相关代码)
- config (项目开发环境配置)
- src (代码目录)
- static (静态资源)
- index.html (访问的主页面)
- package.json (项目基本信息、依赖信息)
通常 src 存放源代码,static 存放静态资源,package.json 存放项目信息以及依赖信息,config 存放配置文件,通过 build 的脚本文件,使用依赖 vue-loader 解析源代码的 vue 文件转化成 js 文件,压缩代码,合并 html 并引入相关 js 文件及资源文件,生成项目文件等操作。
这次主要讲讲 package.json、build 以及 config 文件
二、package.json 文件
{
......
......
......
"scripts": { //npm 命令
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"build": "node build/build.js"
},
"dependencies": { //运行时依赖(生产环境)
"vue": "^2.5.2",
"vue-router": "^3.0.1"
},
"devDependencies": { //开发时依赖(开发环境)
......
......
},
......
......
}
scripts
scripts 定义的是用 node 执行的命令
如:npm run build,就是执行了 build/build.js 文件,
npm run dev,就是执行了 build/webpack.dev.conf.js 文件
dependencies vs devDependencies
dependencies 是运行时依赖(生产环境) npm install --save **(package name)
devDependencies 是开发时的依赖(开发环境) npm install --save-dev **(package name)
dependencies 存放的是本地运行所需的文件,像 babel(JavaScript 转化) 和 vue-loader(vue 文件转化)等依赖
dependencies 存放的是打包时需要运行的依赖
三、 config 文件(项目开发环境配置)
内部目录:
(1) dev.env.js 设置开发环境变量
(2) index.js
(3) prod.env.js 设置生产环境变量
config 文件主要是一些配置环境,重点说说 index.js 文件,其他两个都只有一句代码,设置一个变量表示开发或者生产环境。
index.js
module.exports = {
// 开发模式配置
dev: {
// 文件路径
assetsSubDirectory: 'static', // 资源引用路径
assetsPublicPath: '/', // 生成 index.html 路径
proxyTable: { // 代理
'xxx': { // 代理名称(请求路径带上这个名称时自动转换)
target: 'xxx', // 代理服务器地址
changeOrigin: true,
secure: false,
pathRewrite: {
'^/xxx': '/xxx' // 请求路径重写
}
}
},
// 服务器设置
host: 'localhost', // 测试页面地址
port: 8080, // 测试页面端口号
autoOpenBrowser: true, // 开启服务器时是否自动打开浏览器
// 映射
devtool: 'cheap-module-eval-source-map',
cssSourceMap: true //是否开启css映射
},
//生产环境配置
build: {
// 生成 index.html 模板位置
index: path.resolve(__dirname, '../dist/index.html'),
// 路径
assetsRoot: path.resolve(__dirname, '../dist'), //生成项目位置
assetsSubDirectory: 'static',
assetsPublicPath: '/',
// 映射
productionSourceMap: true,
devtool: '#source-map',
productionGzip: false, // 用于 gzip 压缩判断,看 webpack.prod.conf.js 文件讲解
productionGzipExtensions: ['js', 'css'],
// npm run build --report 构建完成后查看bundle analyzer报告
// process.env 是 node 的全局变量,这里用来读取 npm 命令后面的值 report
// 用于 webpack.prod.conf.js 文件做判断值
bundleAnalyzerReport: process.env.npm_config_report
}
}
四、build 文件(构建项目)
内部目录:
(1) build.js 打包编译入口
(2) check-version.js 检查版本
(3) utils.js 工具代码
(4) vue-loader.conf.js vue-loader 配置
(5) webpack.base.conf.js 基础配置文件
(6) webpack.dev.conf.js 开发环境配置文件
(7) webpack.prod.conf.js 生产模式配置文件
check-version.js 用于检查版本,被引入各个文件之中
utils.js 是工具代码,会设置 css-loader、postcss-loader 等
vue-loader.conf.js 则是配置 vue-loader 解析 vue 文件
重点在其他几个文件
webpack.base.conf.js 基础配置文件
module.exports = {
context: path.resolve(__dirname, '../'), // 目录
entry: { // 入口文件
app: './src/main.js'
},
output: { // 输出内容
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: ......
},
resolve: {
extensions: ['.js', '.vue', '.json'], // 检测文件后缀
alias: { // 指定路径的别名,在引用文件路径中,如果有别名的符号,会被替换成指定的路径。
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
},
module: {
rules: [ // 解析规则配置
vue-loader // vue-loader 解析 vue 文件输出 js 模块
babel-loader // babel-loader 转换 ES6
url-loader // url-loader 把一定大小内的资源变成base64格式
]
}
}
webpack.dev.conf.js 开发环境配置文件
const devWebpackConfig = merge(baseWebpackConfig, { // 合并之前的基础配置文件
module: { // 增加cssSourceMap的功能
rules: utils.styleLoaders({ ...... })
},
devtool: config.dev.devtool, // 定义开发模式,cheap-module-eval-source-map使得开发更快
devServer: { // 定义服务器的一些配置
......
......
},
plugins: [ // 插件
DefinePlugin // 定义 process.env(开发环境)
HotModuleReplacementPlugin // 模块热替换插件
NamedModulesPlugin // 显示模块加载相对路径插件
NoEmitOnErrorsPlugin // 进程遇到错误代码将不会退出,在控制台输出错误日志
HtmlWebpackPlugin // 使用插件生成一个指定的模版
CopyWebpackPlugin // 自定义静态资源目录
]
})
webpack.prod.conf.js 生产模式配置文件
打包到生产环境,和 webpack.dev.conf.js 一样也是先合并基础配置文件,但是插件有些变化。
1.新增了 output 配置,将源码打包成带有 hash 尾缀的不同模块的 js 文件,如 vendor.cd57a1ba620b10849fab.js 。
这里使用 chunkhash 尾缀,根据文件映射,在修改时如果没有修改到当前模块或者当前引用的模块, chunkhash 就不会改变,从而在部署的时候可以减少文件缓存带来的部署问题,是一个优化方案。
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
2.插件
DefinePlugin 定义 process.env(生产环境)
UglifyJsPlugin 代码压缩
OptimizeCSSPlugin 压缩css代码
HtmlWebpackPlugin 生成主页面模板
HashedModuleIdsPlugin 根据模块的相对路径生成一个 hash 作为模块 id
ModuleConcatenationPlugin 作用域提升,加快代码执行速度
CommonsChunkPlugin 提取第三方库和公共模块
// 抽离css代码(webpack打包 css会变成用 js的模块方式引入,有延迟,所以要抽离css)
// 为该文件增加 contenthash 尾缀(contenthash:当前模块的内容变了,hash值才改变)
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css'),
allChunks: true,
}),
额外要注意的插件:
// gzip 压缩插件
if (config.build.productionGzip) { // 判断生产模式下的 productionGzip 值
// 提供带 Content-Encoding 编码的压缩版的资源
const CompressionWebpackPlugin = require('compression-webpack-plugin')
webpackConfig.plugins.push( // 把此插件插入 webpack 插件设置内
new CompressionWebpackPlugin({ ...... })
)
}
// 查看 bundle analyzer 报告插件
if (config.build.bundleAnalyzerReport) { // 在config/index.js中已说明,npm 输入的命令
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
顺便小结一下文件尾缀:
尾缀 | 状态变动 | 使用 |
---|---|---|
hash | 文件变动,立即改变 | 图片等资源 |
chunkhash | 修改到当前模块或者当前引用的模块才改变 | 常用于 js |
contenthash | 当前模块的内容变了,值才改变 | 常用于 css |
build.js
项目打包时执行的文件,npm run build
主要是先删除(rimraf 插件)以前打包的 dist 文件,删除后读取 webpack.prod.conf.js 的设置然后开始 webpack 的构建
五、总结
最后总结一下整个 vue 项目构建流程(主体为 webpack 的构建流程)
启动构建,读取与合并配置参数,加载 Plugin
使用 Loader 递归翻译所有模块。这里是 vue-loader 解析 vue 文件,变成 js 文件 module.exports 大概三个语言模块(html,script,style)。中间穿插 es6 转换,css 转换,资源文件引用增加 hash 尾缀以及 base64 格式转化。
根据依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表。即打包压缩、抽取插件和公共代码,生成 app.[chunkhash].js 、按需加载.[chunkhash].js、vendor.[chunkhash].js 和 manifest.[chunkhash].js
文件 | 来源 |
---|---|
app | 源代码 |
vendor | 抽离 node_modules 依赖及公共模块 |
manifest | 映射各个模块的数据集合,便于快速更替文件 |
最后生成主页面模板引入相关静态资源和 js 文件,把项目输入到 dist 文件夹内。