实用webpack插件之DefinePlugin

栏目: 编程语言 · 发布时间: 5年前

内容简介:通过阅读这篇文章,可以学习到如何使用DefinePlugin插件使得前端项目更加工程化,说清晰点就是如何使用这个插件,在编译阶段根据NODE_ENV自动切换配置文件,提升前端开发效率。DefinePlugin中的每个键,是一个标识符或者通过这些值将内联到代码中,压缩减少冗余。
实用webpack插件之DefinePlugin

通过阅读这篇文章,可以学习到如何使用DefinePlugin插件使得前端项目更加工程化,说清晰点就是如何使用这个插件,在编译阶段根据NODE_ENV自动切换配置文件,提升前端开发效率。

  • DefinePlugin的正确用法
  • 如何使用DefinePlugin添加配置文件,构建期间自动检测环境变化,也就是如何根据NODE_ENV引入配置文件?

DefinePlugin的正确用法

DefinePlugin中的每个键,是一个标识符或者通过 . 作为多个标识符。

typeof

这些值将内联到代码中,压缩减少冗余。

new webpack.DefinePlugin({
    PRODUCTION: JSON.stringify(true),
    VERSION: JSON.stringify('5fa3b9'),
    BROWSER_SUPPORTS_HTML5: true,
    TWO: '1+1',
    'typeof window': JSON.stringify('object'),
    'process.env': {
         NODE_ENV: JSON.stringify(process.env.NODE_ENV)
     }
});
复制代码
console.log('Running App version' + VERSION);
复制代码

plugin不是直接的文本值替换,它的值在字符串内部必须包括 实际引用 。典型的情况是用双引号或者JSON.stringify()进行引用,'"production"',JSON.stringify('production')。

重点:在vue-cli创建的项目中,凡是src下的文件,都可以访问到VERSION这个变量,例如main.js,App.vue等等

我们现在看一下上面的几种类型的key值,在代码中的输出。

console.log(PRODUCTION, VERSION, BROWSER_SUPPORTS_HTML5, TWO, typeof window, process.env);
复制代码
PRODUCTION: true,
VERSION: "5fa3b9",
BROWSER_SUPPORTS_HTML5: true,
TWO: 2,
typeof window: "object",
process.env: {NODE_ENV: "development"},
复制代码

在代码中,我们一般会有以下几种用途:

  • 根据process.env.NODE_ENV区分环境
  • 引入配置文件
  • 根据NODE_ENV引入配置文件 (这个很重要,后面会讲到)

Feature Flag

可以控制新特性和实验特性的开关。

new webpack.DefinePlugin({
    'NICE_FEATURE': JSON.stringify(true),
    'EXPERIMENTAL': JSON.stringify(false),
})
复制代码

process.env.NODE_ENV的正确配置方式是什么?

process: {
    env: {
        NODE_ENV: JSON.stringify('production')
    }
}
复制代码

评价: 非常不好,会overwrite整个process对象,仅仅保留新的NODE_ENV,破坏进程。 原始的process对象包含如下内容 ,包含了当前进程的很多信息。

process {
  title: 'node',
  version: 'v8.11.2',
  moduleLoadList: 
   [ 'Binding contextify',],
  versions: 
   { http_parser: '2.8.0'},
  arch: 'x64',
  platform: 'darwin',
  release: 
   { name: 'node' },
  argv: [ '/usr/local/bin/node' ],
  execArgv: [],
  env: 
   { TERM: 'xterm-256color'},
  pid: 14027,
  features: 
   { debug: false},
  ppid: 14020,
  execPath: '/usr/local/bin/node',
  debugPort: 9229,
  _startProfilerIdleNotifier: [Function: _startProfilerIdleNotifier],
  _stopProfilerIdleNotifier: [Function: _stopProfilerIdleNotifier],
  _getActiveRequests: [Function: _getActiveRequests],
  _getActiveHandles: [Function: _getActiveHandles],
  reallyExit: [Function: reallyExit],
  abort: [Function: abort],
  chdir: [Function: chdir],
  cwd: [Function: cwd],
  umask: [Function: umask],
  getuid: [Function: getuid],
  geteuid: [Function: geteuid],
  setuid: [Function: setuid],
  seteuid: [Function: seteuid],
  setgid: [Function: setgid],
  setegid: [Function: setegid],
  getgid: [Function: getgid],
  getegid: [Function: getegid],
  getgroups: [Function: getgroups],
  setgroups: [Function: setgroups],
  initgroups: [Function: initgroups],
  _kill: [Function: _kill],
  _debugProcess: [Function: _debugProcess],
  _debugPause: [Function: _debugPause],
  _debugEnd: [Function: _debugEnd],
  hrtime: [Function: hrtime],
  cpuUsage: [Function: cpuUsage],
  dlopen: [Function: dlopen],
  uptime: [Function: uptime],
  memoryUsage: [Function: memoryUsage],
  binding: [Function: binding],
  _linkedBinding: [Function: _linkedBinding],
  _events: 
   { newListener: [Function],
     removeListener: [Function],
     warning: [Function],
     SIGWINCH: [ [Function], [Function] ] },
  _rawDebug: [Function],
  _eventsCount: 4,
  domain: [Getter/Setter],
  _maxListeners: undefined,
  _fatalException: [Function],
  _exiting: false,
  assert: [Function],
  config: {},
  emitWarning: [Function],
  nextTick: [Function: nextTick],
  _tickCallback: [Function: _tickDomainCallback],
  _tickDomainCallback: [Function: _tickDomainCallback],
  stdout: [Getter],
  stderr: [Getter],
  stdin: [Getter],
  openStdin: [Function],
  exit: [Function],
  kill: [Function],
  _immediateCallback: [Function: processImmediate],
  argv0: 'node' }
复制代码
'process.env': {
    NODE_ENV: JSON.stringify('production')
}
复制代码

评价: 不好,会overwrite整个process.env对象,破坏进程环境,导致破坏兼容性。 原始的process.env对象包含如下内容 ,包含了当前进程的很多信息。

{ TERM: 'xterm-256color',
  SHELL: '/bin/bash',
  TMPDIR: '/var/folders/lw/rl5nyyrn4lb0rrpspv4szc3c0000gn/T/',
  Apple_PubSub_Socket_Render: '/private/tmp/com.apple.launchd.dEPuHtiDsx/Render',
  USER: 'frank',
  SSH_AUTH_SOCK: '/private/tmp/com.apple.launchd.MRVOOE7lpI/Listeners',
  __CF_USER_TEXT_ENCODING: '0x1F5:0x19:0x34',
  PATH: '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Wireshark.app/Contents/MacOS',
  PWD: '/Users/frank/Desktop/corporation/weidian-crm',
  XPC_FLAGS: '0x0',
  XPC_SERVICE_NAME: '0',
  SHLVL: '1',
  HOME: '/Users/frank',
  LOGNAME: 'frank',
  LC_CTYPE: 'zh_CN.UTF-8',
  _: '/usr/local/bin/node' }
复制代码
'process.env.NODE_ENV': JSON.stringify('production')
复制代码

评价:好。因为仅仅对NODE_ENV值进行修改,不会破坏完整进程,也不会破坏兼容性。

如何使用DefinePlugin添加配置文件,构建期间自动检测环境变化,也就是如何根据NODE_ENV引入配置文件?

情景:开发阶段的接口地址往往与生产阶段的接口地址是不一致的。 例如开发时是development.foo.com而生产时是production.foo.com ,如果需要打包发布,那么需要手动去替换域名或者是一个分支维护一个专门的配置文件,这两种方式是非常笨重的。

  • 手动替换 文件效率低下,每次在development和production见切换都需要进行配置文件的更新,容易出错
  • 配置文件 相对手动替换高级一些,但是不能一次性查看development和production的全部配置信息,需要在分支间切换,效率低下,且不适用于多种环境的配置
  • webpack.DefinePlugin() 全局配置文件,自动检测环境变化,效率高效。

webpack的DefinePlugin正是为我们解决这样一个问题,它维护一个全局的配置文件,在编译期间会自动检测process.env.NODE_ENV,根据当前的环境变量去替换我们的接口域名。

下面我将以一个实例来介绍如何正确使用webpack.DefinePlugin。

/config/api.js

const NODE_ENV = process.env.NODE_ENV;
const config = {
     production: {
        FOO_API: 'production.foo.api.com',
        BAR_API: 'production.bar.api.com',
        BAZ_API: 'production.baz.api.com',
     },
     development: {
        FOO_API: 'development.foo.api.com',
        BAR_API: 'development.bar.api.com',
        BAZ_API: 'development.baz.api.com',
     },
     test: {
        FOO_API: 'test.foo.api.com',
        BAR_API: 'test.bar.api.com',
        BAZ_API: 'test.baz.api.com',
     }
}
module.exports = config[NODE_ENV];
复制代码

webpack.dev.conf.js/webpack.prod.conf.js/webpack.test.conf.js

const apiConfig = require('./config/api');
const webpackConfig = {
    plugins: [
        new webpack.DefinePlugin({
            API_CONFIG: JSON.stringify(apiConfig);
        })
    ]
}
...
复制代码

custom.component.vue

<template>
...
</template>
<script>
// 这里也可以访问到API_CONFIG
export default {
    // 这里无论是data函数,methods对象,computed对象,watch对象,都可以访问到API_CONFIG;
   data() {
       return {
           fooApi: API_CONFIG.FOO_API,
           user:{
               id: '',
               name: '',
           },
           hash: '',
        } 
    },
    computed: {
        userAvator() {
            return `${API_CONFIG.BAR_API}?id=${user.id}&name=${user.name}`
        }
    },
    methods: {
        uploadImage() {
            api.uploadImage({user: `${API_CONFIG.BAZ}\${hash}`})
                 .then(()=>{})
                 .catch(()=>{})
        }
    }
}
</script>
复制代码

上述仅仅适用于vue-cli2.0时代,vue-cli3.0引入了webpack-chain,配置方式大大不同,下文将给出示例。

如何在vue.config.js中,使用使用DefinePlugin添加配置文件,构建期间自动检测环境变化,也就是如何根据NODE_ENV引入配置文件?

vue.config.js

const apiConfig = require('./config/api');

module.exports = {
    chainWebpack: config => {
        config
            .plugin('define')
            .tap(args => { 
                args[0].API_CONFIG = JSON.stringify(apiConfig)
                return args
            })
    }
}
复制代码

需要注意的是,在vue-cli3.0中,我们不能直接SET NODE_ENV=production或者EXPORT NODE_ENV=production。 因为vue-cli-servive有3种模式,serve默认为development,build为production,若想修改vue-cli-service包中的NODE_ENV,需要通过vue-cli-service serve --mode production进行切换。 就像下面这样:

{
  "scripts": {
    "dev": "vue-cli-service serve", // mode默认为development 
    "production": "vue-cli-service serve --mode production", 
  },
}
复制代码

注意:我们只能在development, production或者test 3个模式下进行切换,不能引入类似preproduction之类的自定义node环境,但是实际上这3个环境已经足以满足大多数的开发情况。

为什么vue-cli 3.0中的DefinePlugin可以用config.plugin('define')修改入参?

源码文件base.js 中,有下面的代码:

webpackConfig
      .plugin('define')
        .use(require('webpack/lib/DefinePlugin'), [
          resolveClientEnv(options)
        ])

复制代码

这一点很关键! 我们在vue.config.js中拿到的config.plugin('define'),实际上时vue-service内部创建的webpack.DefinePlugin实例的引用 ! 明确了这一点,我们在以后增强webpack默认插件配置时,需要先到vue-service的源码中寻找一番,看看有没有对应plugin的引用,若有,必须根据vue-service定义的名字直接引用,否则会修改失败。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Ordering Disorder

Ordering Disorder

Khoi Vinh / New Riders Press / 2010-12-03 / USD 29.99

The grid has long been an invaluable tool for creating order out of chaos for designers of all kinds—from city planners to architects to typesetters and graphic artists. In recent years, web designers......一起来看看 《Ordering Disorder》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

SHA 加密
SHA 加密

SHA 加密工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具