webpack多页运用架构系列(七):开辟环境、临盆环境傻傻分不清楚?

本文首发于
Array_Huang的手艺博客——
有用至上,非经作者赞同,请勿转载。

原文地点:
https://segmentfault.com/a/1190000006952432

假如您对本系列文章感兴趣,迎接关注定阅这里:
https://segmentfault.com/blog/array_huang

媒介

开辟环境与临盆环境星散的缘由以下:

  • 在开辟时,不可防止会发生大批debug又或是测试的代码,这些代码不该出现在临盆环境中(也即不该供应给用户)。
  • 在把页面布置到服务器时,为了寻求极致的手艺指标,我们会对代码举行林林总总的优化,比方说殽杂、紧缩,这些手腕往往会完全损坏代码自身的可读性,不利于我们举行debug等事变。
  • 数据源的差异化,比方说在当地开辟时,读取的往往是当地mock出来的数据,而正式上线后读取的自然是API供应的数据了。

假如硬是要在开辟环境和临盆环境用完全一样的代码,那末必然会支付极重的价值,这点想必也不必多说了。

下面主要针对两点来引见怎样星散开辟环境和临盆环境:一是怎样以差别的体式格局举行编译,也即怎样离别构成开辟环境及临盆环境的webpack设置文件;二是在营业代码中怎样依据环境的差别而做出差别的处置惩罚。

怎样星散开辟环境和临盆环境的webpack设置文件

假如同时把一份完全的开辟环境设置文件和一份完全的临盆环境设置文件列在一起举行比较,那末会出现以下三种状况:

  • 开辟环境有的设置,临盆环境不一定有,比方说开辟时须要天生sourcemap来协助debug,又或是热更新时运用到的HotModuleReplacementPlugin
  • 临盆环境有的设置,开辟环境不一定有,比方说用来殽杂紧缩js用的UglifyJsPlugin
  • 开辟环境和临盆环境都具有的设置,但在细节上有所差别,比方说output.publicPath,又比方说css-loader中的minimizeautoprefixer参数。

更主要的是,实际上开辟环境和临盆环境的设置文件的绝大部份都是一致的,关于这一致的部份来讲,我们坚定要消弭冗余,不然后续保护起来不仅贫苦,而且还轻易失足。

怎样做呢?

答案很简朴:分拆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服务器。

怎样做呢?

我参考了很多文章,先大略讲讲我没有采纳的要领:

  • EnvironmentPlugin引入process.env,如许就能够在营业代码中靠process.env.NODE_ENV来推断了。
  • ProvidePlugin来控制在差别环境里加载差别的设置文件(营业代码用的)。

那我用的是什么要领呢?我末了选用的是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

    原文作者:array_huang
    原文地址: https://segmentfault.com/a/1190000006952432
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞