有些时候,一些 npm 包并没有按照规范的方式打包,或者本身 npm 包比较老旧,这时候我们需要修改一些配置,使得 Webpack 正确的处理这些包。
resolve.alias
有些 npm 包不怎么规范,package.json
中 main
字段没有指向正确的文件。或者我们想让 Webpack 加载其他版本的构建结果。此时我们需要通过 resolve.alias
来重新指定模块路径。
const config = {
resolve: {
alias: {
demo: path.resolve(__dirname, 'node_modules/demo/dist/demo.js'),
},
},
};
2
3
4
5
6
7
上面的配置告诉 Webpack 当遇到 demo
开头的模块时,使用指定的路径来寻找。我们还可以将 demo
配置成一个正则来匹配。
比如,我们可以通过 resolve.alias
来加载 React 已经构建好的 .min.js
版本,放弃一些 propTypes
校验,来减小构建大小。
在 loader 中,我们可以通过
resolveLoader.alias
实现同样的效果。
resolve.modules
我们可以通过 resolve.modules
来修改 Webpack 查找模块的地址。比如,默认情况下,Webpack 只会在 node_modules
目录下查找模块,我们通过如下配置
const config = { resolve: { modules: ['demo', 'node_modules'] } };
使得 Webpack 优先从 demo
目录下查找,找不到再去 node_modules
目录下查找模块。
在大项目中,如果我们想自定义查找模块的地址,这个配置项非常有用。
resolve.extensions
默认情况下,Webpack 只会解析 .js
,.json
和 .mjs
文件,我们可以通过 resolve.extensions
来修改。
const config = { resolve: { extensions: ['.js', '.jsx'] } };
这个例子使得 Webpack 可以解析 .jsx
文件。
resolve.plugins
默认情况下,Webpack 会使用目录下的 index
文件来作为模块的返回,resolve.plugins
可以帮助我们对这一行为进行定制。directory-named-webpack-pluginopen in new window 就是一个很好的例子,通过这个插件,我们可以将 import foo from "./foo";
变成 import foo from "./foo/foo.js";
。
babel-plugin-module-resolveropen in new window 这个插件功能类似,只是为 Babel 提供服务。
不处理某些包
一些第三方包,比如 JQuery 通常都是通过 CDN 部署,页面直接引用即可。因此,在 Webpack 配置中我们需要将这一类的包标识为 external
。
const config = { externals: { jquery: 'jquery' } };
有些时候我们为了防止 CDN 出现问题,我们还需要做一些防备手段,当从 CDN 加载失败以后,可以从本服务器进行加载。
<script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
window.jQuery ||
document.write('<script src="js/jquery-3.1.1.min.js"><\/script>');
</script>
2
3
4
5
从 Webpack 5 开始,支持设置 externalsTypeopen in new window 字段,来自定义加载模块的方式。比如设置为
"promise"
,则会异步加载,设置为"import"
则会使用import()
的方式加载。我们还可以针对每一个包做自定义,比如我们可以配置异步加载 JQuery,["jquery", "promise"]
。
处理全局变量
有一些包会使用全局变量,比如 JQuery 中会使用 $
。Webpack 提供了一些处理这些全局变量的方法。
注入全局变量
imports-loaderopen in new window 可以帮助我们将全局变量注入到我们的模块中。在下面的例子中,Webpack 会为每一个模块都注入 import $ from 'jquery';
。
const config = {
module: {
rules: [
{
test: /\.js$/,
loader: 'imports-loader',
options: {
imports: ['default jquery #39;],
},
},
],
},
};
2
3
4
5
6
7
8
9
10
11
12
13
解析全局变量
Webapck 的 ProvidePlugin
插件可以帮助 Webpack 正确的处理模块中的全局变量。
const config = {
plugins: [new webpack.ProvidePlugin({ $: 'jquery' })],
};
2
3
暴露全局变量
有时候我们需要将模块内的一些变量暴露到全局中给其他模块使用。expose-loaderopen in new window 可以实现这个功能。
const config = {
test: require.resolve('react'),
loader: 'expose-loader',
options: {
exposes: ['React'],
},
};
2
3
4
5
6
7
如果你需要在暴露全局变量的时候执行一些逻辑,则可以使用 script-loaderopen in new window。
删除未使用的模块
有些模块会携带很多我们不需要的信息。比如 moment
这个包,会带有很多 locale
文件,这会增加我们的构建大小。我们可以使用 Webpack 的IgnorePlugin
这个插件来忽略这些文件。
const config = {
plugins: [
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/locale$/,
contextRegExp: /moment$/,
}),
],
};
2
3
4
5
6
7
8
如果需要加载某一个特殊的 locale
文件,则可以使用 ContextReplacementPlugin
插件。
const config = {
plugins: [
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /de|fi/),
],
};
2
3
4
5
处理预构建的包
Webpack 在处理一些依赖包的时候,如果使用了预构建(已经构建完毕并压缩过等)的版本,则会报下面这样的错误。
WARNING in ../~/jasmine-promises/dist/jasmine-promises.js
Critical dependencies:
1:113-120 This seems to be a pre-built javascript file. Though this is possible, it's not recommended. Try to require the original source to get better results.
@ ../~/jasmine-promises/dist/jasmine-promises.js 1:113-120
2
3
4
通常情况下,我们有两种方法处理。一种是将解析包的路径指向包的源代码版本。另一种是使用 module.noParse
来跳过处理这个包。
const config = {
module: { noParse: /node_modules\/demo\/index.js/ },
};
2
3
总结
我们在构建的时候可能会碰到各种各样因为依赖包导致的构建问题。Webpack 提供了一些处理这些依赖包的方法,我们可以根据需要使用。
通过 Webpack 我们还可以使用其他包中的全局变量,也可以将自己模块内的信息以全局变量的形式暴露出去。
关注微信公众号,获取最新推送~
加微信,深入交流~