前言
vue-cli 这边作为驱动 webpack 的一个应用
它需要构造 webpack 所需要的上下文, 以及参数
这里 我们来关注一下 vue-cli 这边为 webpack 构造的参数 的相关处理
webpack 这边上下文的配置, 主要分为了几个部分, Entry, Output, Module, Resolve, Plugin, DevServer, Optimization
从一个构造好的 webpackConfig 中也可以看到这个
vue-cli 的 vue-plugin 的加载
内置的 plugin 列表如下, 依次对应于左边的 commands, config 中的各个 js
也是在这个流程中, npm run serve 和 npm run build 产生了一些配置上的差异 导致了一部分结果的差异
如下初始化的 webpackConfig 的配置, 也是基于这几个 vue-plugin
webpackConfig - entry
客户端这边的访问入口
默认的 entry 是 src/main.js, 这个是在 @vue/cli-service/lib/config/base.js 中定义的
也可以手动配置多个 entry
webpackConfig - output
这个定义的是 输出目录, 输出的文件名模板, publicPath 等等
这个主要是在 base.js, app.js 中进行处理的
webpackConfig - module
webpack 的视角, 每一个文件均是 对应于一个 module
这个 module 模块, 就是对应于 webpack 这边需要配置的各种处理
module 的配置主要是在 base.js, assets.js 中进行处理的
比如 vue 文件使用 vue-loader 进行处理
比如图片文件, 更新它的 文件名称, 方式如下 generator
视频文件, 字体文件, 也是同样的道理, 类似的配置
比如 css 文件, 使用 postcss-loader, 再使用 css-loader, 再使用 vue-style-loader 进行加载
比如 scss, sass 文件, 先使用 saas-loader, 再使用 postcss-loader 再使用 css-loader, 再使用 vue-style-loader 进行加载
sass-loader 这边的主要作用是将 sass, scss 格式的输入转换为 css 的输出
postcss-loader 这边主要是将带新特性的 css 的输入 转换为各大浏览器兼容的 css
css-loader 用于支持 css 的 模块化, 压缩, 文件导入 等等特性
vue-style-loader 将 css 来兼容 vue, 将 css 更新为使用 dom 操作来实现目标 css 的样式的效果
webpackConfig - resolve
这个主要是 指的是类似于 占位符的功能
在业务代码中使用了 定义的相关占位符, 然后 webpack 这边对占位符进行解析, 然后 再进行后面的处理流程
比如我们常见的 @, 如下是一个 @ 的使用, 当然 使用的地方 很多
比如这里的 @/components/HelloWorld 等价于 D:\WebstormWorkStations\hello-package\src\components\HelloWorld.vue
{
path: '/HelloWorld',
name: 'HelloWorld',
component: () => import('@/components/HelloWorld')
}
然后一些预定义的变量初始化是在 base.js 中
webpackConfig - plugin
这些插件是 webpack 提供强大功能 的入口之一
这些插件在 serve.js, app.js, base.js 中均有注册
这里的一系列的 plugin 又可以扩展出 很大一片知识点, 这里仅仅是 列举一些常见的解释一下
这些 plugin 依赖于 webpack 的 compiler 的各个钩子
VueLoaderPlugin
这个主要是用于解析 vue 文件, 解析出文件中的 template, script, style
然后后面 babel-loader 对加载之后的结果进行编译, 高于 es5 版本的特性, 更新为兼容 es5 特性的代码
这里是 babel-loader 的相关处理的地方, 下面一个红色箭头是上面 vue-loader 的加载的地方
这里我们可以回顾一下前面 “npm run serve/build 的输出分析” 中的 vue-loader 加载 js 的部分
从这里我们可以看到整个处理流程是 外部请求了 “HelloWord.vue?vue&type=script&lang=js”, 然后接着是 vue-loader 加载 HelloWorld.vue, 接着是 babel-loader 对 vue-loader 处理结果进行处理
DefinePlugin
增加一些 webpack 全局的占位符定义, 比如这里 需要将 process.env.NODE_ENV = “development” 定义进去
然后 这个 applyDefine 会在 parser 上面注册钩子, 如果 JavaScriptParser 解析 *.js 文件的时候, 看到了 process.env.NODE_ENV 将其解析为 “development”
如下是 JavaScriptParser 解析 es.array.push.js 的时候, source 中为 es.array.push.js
第一个 source.substring(8270, 10076) 是第一层 包含 process.env.NODE_ENV 的语句
第二个 source.substring(8564, 8601) 是最具体的一层 包含 process.env.NODE_ENV 的语句
然后由 DefinePlugin 这边添加到 parser 这边的回调进行处理, 将 process.env.NODE_ENV 解析为 development
这也就是我们的 *.js 中可以使用 process.env.NODE_ENV 的原因
FriendlyErrorsWebpackPlugin
创建了 Compiler 之后, plugin 往 Compiler 上面注册了 关注的事件 的回调, 比如这里关心 编译完成 和 发生非法事件
对于 编译完成之后, 输出编译成功, 暴露的服务的信息到控制台, 如果有错误, 输出错误信息到控制台
如下编译成功的日志信息的输出, 就是由 FriendlyErrorPlugins 输出
然后之后的 暴露的端口, 服务信息, 是由 vue-cli 这边注册的回调输出的
我们常见的 warning, error 的信息, 也是从这个插件输出出来的
HtmlWebpackPlugin
这个插件就是用于生成 index.html, 更新占位符, 添加 css, jss 对应的 chunk 等等
这里就是根据 webpackConfig.entry 来生成各个 entry 的地方了, 通常来说 我们只有默认的 src/main.js 一个默认 entry , 情况如下
在 compiler 中获取生成的 css, jss 的相关 chunk, 然后 merge 到 index.html 中
并且这个过程中也提供了相当多的钩子函数, 允许外部程序去介入
最终编译出来的 index.html 如下效果
CopyPlugin
这个 CopyPlugin 就是配置一个 需要拷贝的文件表达式, 配置一个 目标文件夹的路径
然后将 目标需要拷贝的文件, 拷贝到 目标文件夹下面
最常见的就是 app.js 提供的默认的拷贝 public 文件夹的操作, 将 public 下面的文件复制到打包之后的目录下面
比如说, 我这里在 public 下面新增了 1.txt, 2.txt, 1.js, 然后 npm run build 之后查看 dist 目录, 也可以看到新增的 1.txt, 2.txt, 1.js
然后另外的一个比较典型的 CopyPlugin 的使用, 是 mars3d 的提供的测试用例中
它的目的是将 mars3d 的需要相关静态资源拷贝到 public 下面, 去提供服务, 供 mars3d 相关服务使用
webpackConfig - devServer
这个具体的配置项可以参见 webpack-dev-server 的 help, 可以查看所有的配置信息
vue-cli 这边传递下去的默认配置信息如下, 这里可以看到 端口尝试的处理
各种创建 webpack-dev-server 上下文所需要的信息
webpackConfig - optimization
这是一些 打包优化的相关配置, 比如 包的拆分, 移除空包, 包内容的最小化, 压缩 等等功能
webpack 内置的优化功能有这些
我们经常能够调试到的有RealContentHashPlugin 和 SplitChunksPlugin
优化的相关默认配置, 在 vue-cli 中也是在 app.js, base.js 中
webpack 本身提供的默认配置
这个就是 上下文均没有提供的配置的时候, webpack 为一部分必要的配置提供的一部分默认配置, 这里的上下文指的是 用户传入的 或者 vue-cli 传递给 webpack 的
这个主要是在 webpack/lib/config/defaults.js 中, 这里整个 applyWebpackOptionsDefaults 的内容较多, 这里不一一展示
比如我们经常提到的一些 npm run build 和 npm run serve 配置的默认值就是在这里产生的差异, 比如 devtool, minimize, cachedGroups 的默认配置 等等
npm run serve 的输出文件名是类似于 各种名称, 而 npm run build 的输出文件名是类似于 id 的名称, 这个差异是在 applyOptimizationDefaults 中的配置产生的
看这里的 moduleIds, chunkIds 的配置, 如果是 deterministic 就是 hash取模 计算的一个数字标志, named 就是根据 chunkGroup 携带的元数据信息生成的一个友好的名称
这个名称的生成的具体的方式可以参见 “vue_webpack_split_chunk_strategy.docx” 中的 “npm run serve 中的 app.js 中默认情况下的 chunk 的拆分”
完