Webpack node、output.jsonpFunction 配置详解
最近尝试给一些用到 webpack
的项目升级到最新 webpack5
版本,其中遇到了一些问题,我挑了两个比较典型的问题,其中主要涉及到了 webpack
的 node
属性跟 output.jsonpFunction
(webpack5 以前版本)属性,下面我们结合 webpack
的源码来分析一下这两个属性。
开始
这里使用的 webpack
版本为:
- webpack@^4.46.0
- webpack@^5.88.2
首先我们创建一个 webpack4
的项目:
webpack-node1:
mkdir webpack-node2 && cd webpack-node2 && npm init -y
接着安装 webpack4
:
npm install -D webpack@4.46.0 webpack-cli@4.10.0
创建创建一个 src/index.js
入口文件:
mkdir src && touch src/index.js
在项目根目录 webpack-node1
目录下创建一个 webpack 配置文件 webpack.config.js
:
cd .. && touch webpack.config.js
// webpack.config.js
module.exports = {
output: {
publicPath: "./dist/",
},
devtool: false, // 关闭 source-map 功能
};
ok,我们在项目根目录 webpack-node1
下执行一下 webpack 打包命令看效果:
npx webpack build --mode=development
可以看到,因为我们的入口文件 src/index.js
是一个空文件,所以打包后的 dist/main.js
文件除了一些 webpack 的辅助函数外,入口文件里面为空。
最后我们创建一个 test.html
文件来测试:
touch test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webpack4</title>
<script src="./dist/main.js"></script>
</head>
<body>
</body>
</html>
ok,项目我们就创建完了,接下来我们看一下 webpack.node
配置。
Node 配置
我们先看一下 webpack官网 对它的介绍:
这些选项可以配置是否 polyfill 或 mock 某些 Node.js 全局变量。
此功能由 webpack 内部的
NodeStuffPlugin
插件提供。Warning
从 webpack 5 开始,你只能在
node
选项下配置global
、__filename
或__dirname
。如果需要在 webpack 5 下的 Node.js 中填充fs
,请查阅 resolve.fallback 获取相关帮助。node
boolean: false` `object
webpack.config.js
module.exports = { //... node: { global: false, __filename: false, __dirname: false, }, };
从 webpack 3.0.0 开始,
node
选项可能被设置为false
,以完全关闭NodeStuffPlugin
插件。node.global
boolean` `'warn'
Tip
如果你正在使用一个需要全局变量的模块,请使用
ProvidePlugin
替代global
。关于此对象的准确行为,请查看Node.js 文档。
选项:
true
: 提供 polyfill.false
: 不提供任何 polyfill。代码可能会出现ReferenceError
的崩溃。'warn'
: 当使用global
时展示一个警告。node.__filename
boolean` `'mock' | 'warn-mock' | 'eval-only'
选项:
true
: 输入文件的文件名,是相对于context
选项。false
: webpack 不会更改__filename
的代码。在 Node.js 环境中运行时,出文件的文件名。'mock'
: value 填充为'index.js'
。'warn-mock'
: 使用'/index.js'
但是会展示一个警告。'eval-only'
node.__dirname
boolean` `'mock' | 'warn-mock' | 'eval-only'
选项:
true
: 输入 文件的目录名,是相对于context
选项。false
: webpack 不会更改__dirname
的代码,这意味着你有常规 Node.js 中的__dirname
的行为。在 Node.js 环境中运行时,输出 文件的目录名。'mock'
: value 填充为'/'
。'warn-mock'
: 使用'/'
但是会显示一个警告。'eval-only'
以上是 webpack5
的 node
配置的描述。
webpack4
ok,看完了官网的描述,我们来用一下这个 node
配置。
我们修改一下 src/index.js
文件:
// 判断是浏览器环境
const isBrowser = process.browser; // 使用 nodejs 的 process 对象
console.log(isBrowser);
console.log(__dirname); // 使用 nodejs 的 __dirname 全局属性
console.log(global); // 使用 nodejs 全局对象 global
我们重新执行打包命令看效果:
npx webpack build --mode=development
浏览器打开 test.html
文件:
可以看到,即使是 nodejs
环境中的变量,我们在浏览器中仍然可以访问,这是为什么呢?
因为 webpack
提前给我们注入了这些 nodejs
的全局变量,我们来找一下 webpack4
的源码。
node_modules/webpack/lib/node/NodeSourcePlugin.js
:
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const AliasPlugin = require("enhanced-resolve/lib/AliasPlugin");
const ParserHelpers = require("../ParserHelpers");
const nodeLibsBrowser = require("node-libs-browser");
module.exports = class NodeSourcePlugin {
constructor(options) {
this.options = options;
}
apply(compiler) {
const options = this.options;
// 当 webpack.node 配置为 false 的时候关闭该插件
if (options === false) {
// allow single kill switch to turn off this plugin
return;
}
// 获取 nodepollyfill 的依赖地址
const getPathToModule = (module, type) => {
// 配置成 true 的话就去找到对应的 pollyfill 库
if (type === true || (type === undefined && nodeLibsBrowser[module])) {
if (!nodeLibsBrowser[module]) {
throw new Error(
`No browser version for node.js core module ${
module} available`
);
}
return nodeLibsBrowser[module];
// 配置成 mock 就简单模拟一下
} else if (type === "mock") {
return require.resolve(`node-libs-browser/mock/${
module}`);
// 配置成 empty 就返回 undeifned
} else if (type === "empty") {
return require.resolve("node-libs-browser/mock/empty");
} else {
return module;
}
};
// 修改变量为依赖引入
const addExpression = (