webpack - new webpack.DefinePlugin({ // 定义... });

422 阅读3分钟

上一篇文章写了vue反向代理,这篇文章紧接后续。

遇见bug

项目开发完成后,前端人员一般需要打包部署上线,而我在打包的时候出现了一个问题,导致打包不成功,后面发现是webpack的DefinePlugin插件问题,其实也是我对webpack不了解,没有按照插件要求格式写,出现的问题,今天有空,记录一下

分析bug

  • 先来看看报错语句提示

image.png

  • 打开static/js/31.5a6c80708b85cf7e1939.js文件,ctrl+g跳转到88:6600这个代码位置,

image.png

  • 发现这里已经被压缩了,这个地方就是我这上一篇文章中写的prod.env.js写的代理地址,这里写的有问题吗?看一下打包前的样子
'use strict'
module.exports = {
  NODE_ENV: '"production"',
  API_HOST: "http://172.16.4.238:14022",//生产环境中加上这段关键,不然出错
}
  • prod.env.js打包前貌似没有什么问题,只是那个production使用了两个引号有点奇怪,应该也没什么问题,再来看看上面那张打包后的图,箭头位置前面一点,production打包后只有一个引号了,http地址一个引号都没有了,从字符串变成了变量。咦,为什么会这么奇怪呢?难道这里会默认去掉一对引号?试着把http地址也加上两对引号,果然打包成功了。

bug回顾

既然是打包的时候出现的问题,那就从执行npm run build 的时候开始看

  • 先看package.json文件
{
  ...
  "scripts": {
    "d": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev || --host 0.0.0.0",
    "b": "node build/build.js",
    "dev": "node config/dev.js",
    "build": "node config/build.js"
  },
  ...
}

  • 这个项目这打包(npm run b)的时候执行build.js,再看看build.js有什么
'use strict'
require('./check-versions')()

process.env.NODE_ENV = 'production'

const ora = require('ora')
const rm = require('rimraf')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
const config = require('../config')
const webpackConfig = require('./webpack.prod.conf')

const spinner = ora('building for production...')
spinner.start()

rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
  if (err) throw err
  webpack(webpackConfig, (err, stats) => {
    spinner.stop()
    if (err) throw err
    process.stdout.write(stats.toString({
      colors: true,
      modules: false,
      children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
      chunks: false,
      chunkModules: false
    }) + '\n\n')

    if (stats.hasErrors()) {
      console.log(chalk.red('  Build failed with errors.\n'))
      process.exit(1)
    }

    console.log(chalk.cyan('  Build complete.\n'))
    console.log(chalk.yellow(
      '  Tip: built files are meant to be served over an HTTP server.\n' +
      '  Opening index.html over file:// won\'t work.\n'
    ))
  })
})

  • build.js里面先是声明了环境,然后引入了一些模块,主要运用的代码时webpack,那就看看build.js里面webpack相关的东西,关于webpack,build.js引入了webpack.prod.conf.js文件,再去到webpack.prod.conf.js文件看看

image.png

image.png

  • webpack.prod.conf.js文件里面引入了prod.env.js文件,在下面的DefinePlugin插件里面使用了,bug的真相终于要浮出水面了。

  • 从执行打包命令 npm run b 开始,执行 build.js ---> webpack.prod.conf.js ---> prod.env.js,前面都是引入文件,不会也不应有什么问题,唯一有问题的地方那就是这一块,终于锁定bug位置了

image.png

  • 那这个DefinePlugin又是什么呢?直接翻阅webpack官方文档,找到DefinePlugin,看一遍,不是很明白,但是官网写了为什么要加两个引号,再去百度搜DefinePlugin,看了好几篇文章,终于是弄明白了。

image.png

image.png

bug产生原因解释

  • DefinePlugin在编译的时候会生成一个全局变量,在编译的时候,将变量对应的值直接替换到代码中,如果只写一个引号,取到的值就是一个未定义变量,写了两个引号就是一个字符串。

  • 之前在DefinePlugin里面定义了一个对象

new webpack.DefinePlugin({
      'process.env': env
    }),
  • 那么就会在全局有一个process.env对象
process.env = {
  NODE_ENV: '"production"',
  API_HOST: '"http://172.16.4.238:14022"',//生产环境中加上这段关键,不然出错
}
  • 在后面文件使用时出现问题
process.env.NODE_ENV === 'production' ? true : false
  • DefinePlugin插件使用后就变成了这样,一个变量production与一个字符串"production"进行比较,就出现了问题,http地址那里同理,所以需要使用两个引号,来保证我们拿到的值始终为正确格式。
production === 'production' ? true : false

参考文章:'segmentfault.com/q/101000001…'