解析 vue-cli 如何构建项目

vue-cli

用 vue-cli 直接生成一个 vue 项目很简单方便,不过要想深入学习并掌控 vue 项目,了解项目是如何建构的是很必要,今天就来一边学习一边试着分析。

本文 vue-cli 版本 2.9.6

一、初始化目录结构

vue 主要文件目录:

  1. build (构建项目相关代码)
  2. config (项目开发环境配置)
  3. src (代码目录)
  4. static (静态资源)
  5. index.html (访问的主页面)
  6. 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 文件夹内。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章