webpack多页应用架构系列(七):开发环境、生产环境傻傻分不

2016-09-30  本文已影响0人  Array_Huang

本文首发于Array_Huang的技术博客——实用至上,非经作者同意,请勿转载。
原文地址:https://segmentfault.com/a/1190000006952432
如果您对本系列文章感兴趣,欢迎关注订阅这里:https://segmentfault.com/blog/array_huang

前言

开发环境与生产环境分离的原因如下:

如果硬是要在开发环境和生产环境用完全一样的代码,那么必然会付出沉重的代价,这点想必也不用多说了。

下面主要针对两点来介绍如何分离开发环境和生产环境:一是如何以不同的方式进行编译,也即如何分别形成开发环境及生产环境的webpack配置文件;二是在业务代码中如何根据环境的不同而做出不同的处理。

如何分离开发环境和生产环境的webpack配置文件

如果同时把一份完整的开发环境配置文件和一份完整的生产环境配置文件列在一起进行比较,那么会出现以下三种情况:

更重要的是,实际上开发环境和生产环境的配置文件的绝大部分都是一致的,对于这一致的部分来说,我们坚决要消除冗余,否则后续维护起来不仅麻烦,而且还容易出错。

怎么做呢?

答案很简单:分拆webpack配置文件成N个小module。原先我们是一个完整的配置文件,有好几百行,从头看到尾都头大了,更别说分离不分离的了。下面来看看我分离的结果:

├─webpack.dev.config.js # 开发环境的webpack配置文件(无实质内容,仅为组织整理)
├─webpack.config.js # 生产环境的webpack配置文件(无实质内容,仅为组织整理)
├─webpack-config # 存放分拆后的webpack配置文件
  ├─entry.config.js # webpack配置中的各个大项,这一级目录里的文件都是
  ├─module.config.js
  ├─output.config.js
  ├─plugins.dev.config.js # 俩环境配置中不一致的部分,此文件由开发环境配置文件webpack.dev.config.js来加载
  ├─plugins.product.config.js # 俩环境配置中不一致的部分,此文件由生产环境配置文件webpack.config.js来加载
  ├─resolve.config.js
  │  
  ├─base # 主要是存放一些变量
  │   ├─dir-vars.config.js
  │   ├─page-entries.config.js
  │      
  ├─inherit # 存放生产环境和开发环境相同的部分,以供继承
  │   ├─plugins.config.js
  │      
  └─vendor # 存放webpack兼容第三方库所需的配置文件
      ├─eslint.config.js
      ├─postcss.config.js

文件目录结构看过了,接下来看一下我是如何组织整理最后的配置文件的:

/* 开发环境webpack配置文件webpack.dev.config.js */
module.exports = {
  entry: require('./webpack-config/entry.config.js'),

  output: require('./webpack-config/output.config.js'),

  module: require('./webpack-config/module.config.js'),

  resolve: require('./webpack-config/resolve.config.js'),

  plugins: require('./webpack-config/plugins.dev.config.js'),

  eslint: require('./webpack-config/vendor/eslint.config.js'),

  postcss: require('./webpack-config/vendor/postcss.config.js'),
};

这样,你就可以很轻松地处理开发/生产环境配置文件中相同与不同的部分了。

如何分别调用开发/生产环境的配置文件呢?

还记得我在《webpack多页应用架构系列(二):webpack配置常用部分有哪些?》里讲过,我们在控制台调用webpack命令来启动打包时,可以添加上--config参数来指定webpack配置文件的路径吗?我们可以配合上npm scripts来使用,在package.json里定义:

  "scripts": {
    "build": "node build-script.js && webpack --progress --colors",
    "dev": "node build-script.js && webpack --progress --colors --config ./webpack.dev.config.js",
    "watch": "webpack --progress --colors --watch --config ./webpack.dev.config.js"
  },

这样一来,当我们开发的时候就可以使用npm run devnpm run watch,而到要上线打包的时候就运行npm run build

业务代码如何判断生产/开发环境

在业务代码里要判断生产/开发环境其实很简单,只需一个变量即可:

if (IS_PRODUCTION) {
    // 做生产环境该做的事情
} else {
    // 做开发环境该做的事情
}

这么一来,关键就在于这变量IS_PRODUCTION是怎么来的了。

在我还没分离开发和生产环境时,我用的办法是,开发时在业务代码所使用的配置文件中把这变量设为false,而在最后打包上线时就手动改为true。这种方法我用过一段时间,非常繁琐,而且经常上线后发现,我嘞个去怎么ajax读的是我本地的mock服务器。

怎么做呢?

我参考了许多文章,先粗略讲讲我没有采用的方法:

那我用的是什么方法呢?我最后选用的是DefinePlugin

举个官方例子,其大概用法是这样的:

new webpack.DefinePlugin({
    PRODUCTION: JSON.stringify(true),
    VERSION: JSON.stringify("5fa3b9"),
    BROWSER_SUPPORTS_HTML5: true,
    TWO: "1+1",
    "typeof window": JSON.stringify("object")
})

DefinePlugin可能会被误认为其作用是在webpack配置文件中为编译后的代码上下文环境设置全局变量,但其实不然。它真正的机制是:DefinePlugin的参数是一个object,那么其中会有一些key-value对。在webpack编译的时候,会把业务代码中没有定义(使用var/const/let来预定义的)而变量名又与key相同的变量(直接读代码的话的确像是全局变量)替换成value。例如上面的官方例子,PRODUCTION就会被替换为trueVERSION就会被替换为'5fa3b9'(注意单引号);BROWSER_SUPPORTS_HTML5也是会被替换为trueTWO会被替换为1+1(相当于是一个数学表达式);typeof window就被替换为'object'了。

再举个例子,比如你在代码里是这么写的:

if (!PRODUCTION)
    console.log('Debug info')
if (PRODUCTION)
    console.log('Production log')

那么在编译生成的代码里就会是这样了:

if (!true)
    console.log('Debug info')
if (true)
    console.log('Production log')

而如果你用了UglifyJsPlugin,则会变成这样:

console.log('Production log')

如此一来,只要在俩环境的配置文件里用DefinePlugin分别定义好IS_PRODUCTION的值,我们就可以在业务代码里进行判断了:

  /* global IS_PRODUCTION:true */
  if (!IS_PRODUCTION) {
    console.log('如果你看到这个Log,那么这个版本实际上是开发用的版本');
  }

需要注意的是,如果你在webpack里整合了ESLint,那么,由于ESLint会检测没有定义的变量(ESLint要求使用全局变量时要用window.xxxxx的写法),因此需要一个global注释声明(/* global IS_PRODUCTION:true */)IS_PRODUCTION是一个全局变量(当然在本例中并不是)来规避warning。

示例代码

诸位看本系列文章,搭配我在Github上的脚手架项目食用更佳哦(笑):Array-Huang/webpack-seed(https://github.com/Array-Huang/webpack-seed)

附系列文章目录(同步更新)

本文首发于Array_Huang的技术博客——实用至上,非经作者同意,请勿转载。
原文地址:https://segmentfault.com/a/1190000006952432
如果您对本系列文章感兴趣,欢迎关注订阅这里:https://segmentfault.com/blog/array_huang

上一篇下一篇

猜你喜欢

热点阅读