Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DefinePlugin 三问 #1

Open
lessfish opened this issue Apr 4, 2019 · 0 comments
Open

DefinePlugin 三问 #1

lessfish opened this issue Apr 4, 2019 · 0 comments

Comments

@lessfish
Copy link
Contributor

lessfish commented Apr 4, 2019

官方文档 | 源码

使用方法不多做介绍,它的最大作用是可以定义全局变量,每个 js 文件中都能访问到定义的变量(但是注意,不能用 window.xx 访问到)

我们经常用它来定义全局环境变量,从而判断开发环境还是生产环境。比如 Vue 的 环境变量和模式 的底层实现就是 webpack.DefinePlugin

使用它的过程中我有三个疑问:

  1. 该 plugin 核心实现是怎样?
  2. 变量值为 string 时,为什么要额外用 JSON.stringify? 比如 VERSION: JSON.stringify('5fa3b9')
  3. 布尔值到底要不要 JSON.stringify? 因为文档里好像都有用

核心实现

简单点理解,DefinePlugin 的核心实现就是 字符串替换 而已

一开始我以为它的实现是手动在每个模块中注入变量,跟 imports-loader 功能类似,但是它比我想象中的强大,直接在编译阶段把这事做完了,我们可以看看 webpack 编译后的代码,可以看到源代码中的变量已经被替换成 DefinePlugin 所定义的变量值了

// webpack.config.js
new webpack.DefinePlugin({
  'process.env.NODE_ENV': JSON.stringify('prod')
})

// 源码
console.log(process.env.NODE_ENV)

// 编译后
console.log("prod")

抛开 DefinePlugin 其实 webpack 本身就做了不少事情,比如:

// 源码
if (true === true) console.log(123)

// 编译后
if (true) console.log(123)

实际上,DefinePlugin 远比字符串替换做的多,比如 window.xx 它就不会被替换,如果定义了局部变量,也不会被替换成 DefinePlugin 中定义的同名变量,这需要 webpack 解析阶段的进一步判断(webpack 会将源码解析成 AST)

另外,我们经常在程序中看到 process.env.NODE_ENV,也会在 npm scripts 中看到诸如 cross-env NODE_ENV=xxx xxx 这样的命令,process 是 Node 中的东西,客户端是没有的,最终生成的 js 代码里是没有 process 的,在客户端代码中,webpack 在编译的时候时候就把这些变量替换掉了,一般需要搭配 DefinePlugin、babel-plugin-transform-inline-environment-variables 等工具使用,详见 这个 issue

为什么字符串要 JSON.stringify

理解了它的核心是字符串替换,这个就不难理解了

// webpack.config.js
new webpack.DefinePlugin({
  VERSION: JSON.stringify('5fa3b9')
})

大概这么个过程:

let sourceCode = `console.log(VERSION)`
sourceCode.replace('VERSION', JSON.stringify('5fa3b9'))

如果不加 JSON.stringify:

let sourceCode = `console.log(VERSION)`
sourceCode.replace('VERSION', '5fa3b9')

替换后就成了 console.log(5fa3b9),是个错误语句

如果不使用 JSON.stringify('5fa3b9'),也可以用 "'5fa3b9'"

布尔值需要 JSON.stringify 吗

看了前面,这个就不难推断了,事实上,布尔值值无论加不加 JSON.stringify 都可以,因为 replace 的时候会自动转为字符串

let sourceCode = `console.log(isTrue)`
// 自动将 true 转为字符串
sourceCode.replace('isTrue', true)

这三种形式效果一样:

new webpack.DefinePlugin({
  num1: 0,
  num2: '0',
  num3: JSON.stringify(0),
  bool1: true,
  bool2: 'true',
  bool3: JSON.stringify(true)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant