Skip to main content

公共库提取

在打包多个页面时,他们会共享一些公共的代码,比如:React、React-DOM 等,默认 webpack 的每个 entry 会把这些依赖的代码都打包到 index.js 文件中去,这就导致如果用户访问了多个这些页面,公共库的代码其实是重复加载的。所以一般会把多页面公用的类库单独提取出来打包成一个 js 文件。

目标

把公共库单独提取出来打包成一个 js 文件,并且把这个 js 文件引入到所有页面中。

提取 shared lib

首先给 webpack 指定一个公共库的 entry:

scripts/getScreens.js#createEntries
...
const createEntries = (screens) => {
/** @type {import('webpack').EntryObject} */
const entryData = {};
entryData['shared'] = ['react', 'react-dom'];
...
};

然后给每个 entry 添加dependOn以指定公共库依赖,给 HtmlWebpackPlugin 实例的 chunks 添加shared的 entry:

scripts/getScreens.js#createEntries
const createEntries = (screens) => {
/** @type {import('webpack').EntryObject} */
const entryData = {};
entryData['shared'] = ['react', 'react-dom'];
/** @type {Array<import('html-webpack-plugin')>} */
const htmlEntries = [];

screens.forEach((screen) => {
const screenNameIndex = screen.entryJs.indexOf('screen/');
const entryFileNameBaseDist = screen.entryJs
.substring(screenNameIndex)
.replace(/\.js$/, '');

entryData[entryFileNameBaseDist] = {
import: [screen.entryJs],
filename: '[name].js',
dependOn: ['shared'],
};

htmlEntries.push(
new HtmlWebpackPlugin({
chunks: ['shared', entryFileNameBaseDist],
filename: `${entryFileNameBaseDist}.html`,
template: screen.entryHtml,
})
);
});

return { entryData, htmlEntries };
};

执行下npm run dev,就会发现 dist 下多了一个 shared.js 文件,并且在 index.html 中引入了 shared.js。

预加载公共配置文件

项目中一般会在各个页面预加载公共配置文件,比如全局配置,全局 css 等等,这就需要在每个 entry 入口文件里都要引用一下这个公共配置,不过我们不想在每个 entry 入口文件里引入,而是通过 webpack 把这个公共文件引入到 entry 中。

首先创建一个公共文件:

src/autoload.ts
console.log('autoload');

修改 getScreens.js:

scripts/getScreens.js@createEntries
const createEntries = (screens) => {
/** @type {import('webpack').EntryObject} */
const entryData = {};
entryData['shared'] = ['react', 'react-dom'];
/** @type {Array<import('html-webpack-plugin')>} */
const htmlEntries = [];

const autoloadFile = path.resolve(__dirname, '../tsc_outputs/src/autoload.js');

screens.forEach((screen) => {
const screenNameIndex = screen.entryJs.indexOf('screen/');
const entryFileNameBaseDist = screen.entryJs
.substring(screenNameIndex)
.replace(/\.js$/, '');

entryData[entryFileNameBaseDist] = {
import: [autoloadFile, screen.entryJs],
dependOn: ['shared'],
};

htmlEntries.push(
new HtmlWebpackPlugin({
chunks: ['shared', entryFileNameBaseDist],
filename: `${entryFileNameBaseDist}.html`,
template: screen.entryHtml,
})
);
});

return { entryData, htmlEntries };
};

执行下npm run dev,启动 web 服务打开页面,会发现页面会 console.log 出来 autoload。