webpack多入口配置

随着自己的项目开发的越来越复杂,项目深度和广度都在慢慢增加,现在项目的打包已经不再是立等可取了,而是慢慢的变成按分钟计算的等待。其中的webpack配置也越来月复杂,其实看到vita的打包速度内心有点期待的,但是目前项目的配置项实在太多,迁移成本比较高就先凑合着用。

多入口配置

网页还是需要一点SEO的,同时也不希望把所有内容都一股脑的放到某个应用当中,所以目前项目是多入口的,每个页面都能做到毫秒级加载。

入口扫描

多入口即多个entry,每个entry都会被打包成单独的一个js入口,同时配置好HtmlWebpackPlugin让每个entry都和对应的页面一一对应。这一步放在入口扫描中来做。

扫描流程

flowchart TB
  A["扫描指定目录下的所有文件"] 
  B["是否存在对应的入口文件"]
  C["对应的入口文件是否被使用"]
  D["被使用的入口才会被打包"]
  E["有单独的配置文件则使用它"]
  F["将其放入到插件列表中"]
  A-->B-->C-->D-->E-->F

特定页面单独配置

对于某些页面的单独配置,他可能是脚本或css的引用地址,使用方法如下

1
2
3
4
5
6
7
8
9
10
<% if ( htmlWebpackPlugin.options.separately.script.length > 0 ) {%>
<% for ( const script of htmlWebpackPlugin.options.separately.script ) {%>
<script type="application/javascript" src="<%= script %>"></script>
<% } %>
<% } %>
<% if ( htmlWebpackPlugin.options.separately.css.length > 0 ) {%>
<% for ( const css of htmlWebpackPlugin.options.separately.css ) {%>
<link rel="stylesheet" href="<%= css %>">
<% } %>
<% } %>

示例代码片段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
*
* @param {string} file
* @param {object} entry 入口对象
* @param {any} plugins 插件数组
*/
function readExample(file, entry, plugins) {
// 扫描指定目录下的所有文件
const fileList = fs.readdirSync('./'+file);
fileList.forEach((e)=>{
const filePath = './'+file+'/'+e;
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
// 是否存在对应的入口文件
let tsjsPath = ()=>{
for (const e of ['ts', 'tsx', 'js', 'jsx']) {
const tsjsFilePath = filePath+'/main.'+e;
if (
fs.existsSync(tsjsFilePath) &&
fs.statSync(tsjsFilePath).isFile()
) {
return tsjsFilePath;
}
}
};

tsjsPath = tsjsPath();
if (tsjsPath) {
const entryKey = file+'/'+e;
//对应的入口文件是否被使用
if (process.env.NODE_ENV==='production' &&
!usedPath.includes(entryKey)) {
console.log('run with production,ignore not used page:'+entryKey);
return;
}

// 被使用的入口才会被打包
entry[entryKey]=tsjsPath;
const htmlWebpackPluginOptions = {
filename: './' + file + '/' + e + '.html',
template: './' + file + '/template.ejs',
title: `${file}-${e}`,
chunks: [entryKey, 'manifest', 'vendor'],
};
// 有单独的配置文件则使用它
const separately = './'+file+'/'+e+'/template.js';
if (fs.existsSync(separately)) {
const json = require('.'+separately);
htmlWebpackPluginOptions.separately =JSON.parse(JSON.stringify(json));
}
// 将其放入到插件列表中
plugins.push(new HtmlWebpackPlugin(htmlWebpackPluginOptions));
}
}
});
}

使用示例

最后只需要将entryplugins放入到webpack的配置项中即可配置多入口

1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports = {
//...
entry: {
home: './home.js',
about: './about.js',
contact: './contact.js',
...entry // 扫描到的入口对象
},
plugins: [].concat([
new webpack.ProgressPlugin(),
new HtmlWebpackPlugin({ template: './src/index.html' }),
],plugins), // 对应的打包插件
};