更新内容的时候已经到了2020.03.06,当时实际问题产生和解决大概实在2018年,如今webpack已经到了5的版本,既然以前开过头还是梳理下内容,因为新冠肺炎在家呆着,没远程办公就在家看看整理下
多entry介绍
多entry只是相对于单页应用来说,常规的网站每个页面都是一个entry,单页和多页各有好坏,具体的看自己的场景适合哪种。
个人偏向多entry + entry内的单页应用,按大模块划分为一个个entry,entry内再做单页应用,当然小项目就不必要这么做…
过程中遇到的问题比下面这些要多的多,主要记录几个印象深刻的
预发布和生产等不同环境因为cdn地址不同需要重复构建的问题
项目有很多套运行环境,比如 开发环境、测试环境、预发布环境 。每一套环境cdn地址是不同的,所以导致不同环境都需要重新构建。
前期方案:
大致三个步骤,处理之后可以解决资源路径在不同环境下的正常引用。
- 动态配置
__webpack_public_path__
可以解决js文件中导入的资源文件路径;
1
2
3
4
5
6
7 // publicPath.js 读取全局变量
__webpack_public_path__ = `${window.CDN_PATH || ''}/`; // eslint-disable-line
// entry, 为每一个entry注入该文件
{
index: ['publicPath.js', 'index.js']
}
- ExtractText提取的css文件中的路径通过配置ExtractTextPlugin styleLoader publicPath = ‘../‘ 相对路径
1
2
3
4
5 ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader',
publicPath: '../' // css内资源变更为相对路径
});
- 调整entry的key为一层路径转化文件名中的/保持文件路径都是平级,结合第二条相对路径,即可保证css正确加载图片等资源文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 由于entry文件路径存在多级路径
所以先转换entry名为平级,如 index/user.js
转换entry key为 index/user 到 index_user.
// 保证打包后文件结构:
js
1.js
index_user.js
css
1.css
2.css
index_user.css
img
xx.png
xx.jpg
升级支持css内联打包后再次出现问题:
内联后内联css文件中的路径是相对的html文件,而原本的css相对路径都是基于css文件路径,再次导致css图片、字体等404
最终方案:
- 不同环境依旧使用不同的publicPath配置多次构建。
- 如果不需要内联可以采用方案一。
- 采用发布系统做路径替换也可以解决。
- 或者测试自动化发布流程接入之后就无所谓构建两次。
这个问题是在前期项目发布工程不够完善的情况下,不同环境测试都需要研发来协助编辑,费事费力,后面自动化之后这些问题也可以忽略不计。
ExtractText 导致 style-loader丢失的问题
ExtractText 提取css后导致styleLoader
模块丢失,最终需要异步插入style标签地方,会call不到模块,无法加载异步样式
参考:
https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/456
https://github.com/lavas-project/lavas/issues/85
解决方案如下两种:
- 通过配置 ExtractTextPlugin allChunks: true ,提取所有css,就不会再需要styleLoader来动态插入 style 标签了。
- 在entry文件手动导入 style-loader/lib/addStyles 和 css-loader/lib/css-base,Vue项目也可以导入 vue-style-loader/lib/addStylesClient 和 css-loader/lib/css-base;
ExtractText 多entry无法按需加载css的问题
问题:
多entry下,extractText 提取css无法按需加载,allChunks 只能配置 true。
官方文档要求在使用了CommonsChunkPlugin插件之后只能配置allChunks为true,实际CommonsChunkPlugin提取资源也是产生了新的entry,而我们的实际开发场景必然会需要按需的操作。
不支持原因:
模块 moduleA 包含css,同时被entry1同步导入,entry2异步导入。如下图:
extractText 使用的提取规则:
如果模块被同步导入过就提取,这样就会导致css被提取到entry1.css, entry2 在异步导入的时候丢失了 a.css,这也是官方要求多entry必须allChunks的原因。
解决方案:
修改插件源码调整提取规则只要被异步导入过就不提取,这样也会有问题, entry1的css会变成js执行插入,如果是关键首屏css样式,会导致一次明显的页面闪动。
最终通过 Async.css 中@import ‘a.css’,postcss 处理的时候做内容复制,属于不同module,做到维护一份源码
webpack4 mini-css-extract
在webpack4的时代 mini-css-extract 插件已经解决了这个问题,会在最后对每个同步和异步chunk提取出css文件,也就是官方说的 异步加载,不重复编译,性能更好
。个人觉得如果可以针对异步的chunk配置是否提取出css文件会更好,可以让每个异步模块少一个css请求,当然随着http2通道复用,多个小文件的下载也不见得更慢。
顺便说下 CommonsChunkPlugin 配置需要顺序的问题
最后
在webpack3时代 ExtractText、CommonsChunkPlugin 都是相当的难以使用,CommonsChunkPlugin 会发现不管如何配置都很难控制到自己想要的精细程度,缺少提取优先级也有些难以理解,现在新的版本部分问题已经不复存在或者有了更好的解决方案…