为什么我们要做三份 Webpack 配置文件

时至今日,Webpack 已经成为前端工程必备的基础工具之一,不仅被广泛用于前端工程发布前的打包,还在开发中担当本地前端资源服务器(assets server)、模块热更新(hot module replacement)、API Proxy 等角色,结合 ESLint 等代码检查工具,还可以实现在对源代码的严格校验检查。


正如上文中提到的,前端从开发到部署前都离不开 Webpack 的参与,而 Webpack 的默认配置文件只有一个,即 webpack.config.js,那么问题来了,开发期和部署前应该使用同一份 Webpack 配置吗?答案肯定是否定的,既然 webpack.config.js 是一个 JS 文件,我们当然可以在文件里写 JavaScript 业务逻辑,通过读取环境变量 NODE_ENV 来判断当前是在开发(dev)时还是最终的生产环境(production),然而很多同学习惯把这两者的配置都混写在根目录下的 webpack.config.js,通过很多零散的 if…else 来“临时”决定某一个 plugin 或者某一个 loader 的配置项,随着 loaders 和 plugins 的不断增加,久而久之 webpack.config.js 变得原来越隆长,代码的可读性和可维护性也大大下降。


我想通过本文来介绍一种用 3 个 JS 文件来配置 Webpack 的方法,这里借鉴了很多开源项目的配置,同时也结合了我们自己在开发中碰到的种种问题解决方案。


本文中提及的配置基于 Webpack 2 或以上,建议使用 3.0 及以上版本


开发环境与生产环境的区别


开发环境


  • NODE_ENV 为 development

  • 启用模块热更新(hot module replacement)

  • 额外的 webpack-dev-server 配置项,API Proxy 配置项

  • 输出 Sourcemap


生产环境


  • NODE_ENV 为 production

  • 将 React、jQuery 等常用库设置为 external,直接采用 CDN 线上的版本

  • 样式源文件(如 css、less、scss 等)需要通过 ExtractTextPlugin 独立抽取成 css 文件

  • 启用 post-css

  • 启用 optimize-minimize(如 uglify 等)

  • 中大型的商业网站生产环境下,是绝对不能有 console.log() 的,所以要为 babel 配置 Remove console transform


这里需要说明的是因为开发环境下启用了 hot module replacement,为了让样式源文件的修改也同样能被热替换,不能使用 ExtractTextPlugin,而转为随 JS Bundle 一起输出。


你需要三份配置文件


1. webpack.base.config.js


在 base 文件里,你需要将开发环境和生产环境中通用的配置集中放在这里:


const CleanWebpackPlugin = require('clean-webpack-plugin');

const path = require('path');

const webpack = require('webpack');

 

// 配置常量

// 源代码的根目录(本地物理文件路径)

const SRC_PATH = path.resolve('./src');

// 打包后的资源根目录(本地物理文件路径)

const ASSETS_BUILD_PATH = path.resolve('./build');

// 资源根目录(可以是 CDN 上的绝对路径,或相对路径)

const ASSETS_PUBLIC_PATH = '/assets/';

 

module.exports = {

  contextSRC_PATH, // 设置源代码的默认根路径

  resolve{

    extensions['.js', '.jsx']  // 同时支持 js 和 jsx

  },

  entry{

    // 注意 entry 中的路径都是相对于 SRC_PATH 的路径

    vendor'./vendor',

    a['./entry-a'],

    b['./entry-b'],

    c['./entry-c']

  },

  output{

    pathASSETS_BUILD_PATH,

    publicPathASSETS_PUBLIC_PATH,

    filename'./[name].js'

  },

  module{

    rules[

      {

        enforce'pre',  // ESLint 优先级高于其他 JS 相关的 loader

        test: /\.jsx?$/,

        exclude: /node_modules/,

        loader'eslint-loader'

      },

      {

        test: /\.jsx?$/,

        exclude: /node_modules/,

        // 建议把 babel 的运行时配置放在 .babelrc 里,从而与 eslint-loader 等共享配置

        loader'babel-loader'

      },

      {

        test: /\.(png|jpg|gif)$/,

        use:

        [

          {

            loader'url-loader',

            options:

            {

              limit8192,

              name'images/[name].[ext]'

            }

          }

        ]

      },

      {

        test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,

        use:

        [

          {

            loader'url-loader',

            options:

            {

              limit8192,

              mimetype'application/font-woff',

              name'fonts/[name].[ext]'

            }

          }

        ]

      },

      {

        test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,

        use:

        [

          {

            loader'file-loader',

            options:

            {

              limit8192,

              mimetype'application/font-woff',

              name'fonts/[name].[ext]'

            }

          }

        ]

      }

    ]

  },

  plugins[

    // 每次打包前,先清空原来目录中的内容

    new CleanWebpackPlugin([ASSETS_BUILD_PATH], { verbosefalse }),

    // 启用 CommonChunkPlugin

    new webpack.optimize.CommonsChunkPlugin({

      names'vendor',

      minChunksInfinity

    })

  ]

};


2. webpack.dev.config.js


这是用于开发环境的 Webpack 配置,继承自 base:


const webpack = require('webpack');

 

// 读取同一目录下的 base config

const config = require('./webpack.base.config');

 

// 添加 webpack-dev-server 相关的配置项

config.devServer = {

  contentBase'./',

  hottrue,

  publicPath'/assets/'

};

// 有关 Webpack 的 API 本地代理,另请参考 https://webpack.github.io/docs/webpack-dev-server.html#proxy

 

config.module.rules.push(

  {

    test: /\.less$/,

    use[

      'style-loader',

      'css-loader',

      'less-loader'

    ],

    exclude: /node_modules/

  }

);

 

// 真实场景中,React、jQuery 等优先走全站的 CDN,所以要放在 externals 中

config.externals = {

  react'React',

  'react-dom''ReactDOM'

};

 

// 添加 Sourcemap 支持

config.plugins.push(

  new webpack.SourceMapDevToolPlugin({

    filename'[file].map',

    exclude['vendor.js'] // vendor 通常不需要 sourcemap

  })

);

 

// Hot module replacement

Object.keys(config.entry).forEach((key) => {

  // 这里有一个私有的约定,如果 entry 是一个数组,则证明它需要被 hot module replace

  if (Array.isArray(config.entry[key])) {

    config.entry[key].unshift(

      'webpack-dev-server/client?http://0.0.0.0:8080',

      'webpack/hot/only-dev-server'

    );

  }

});

config.plugins.push(

  new webpack.HotModuleReplacementPlugin()

);

 

module.exports = config;


3. webpack.config.js


这是用于生产环境的 webpack 配置,同样继承自 base:


const webpack = require('webpack');

const ExtractTextPlugin = require('extract-text-webpack-plugin');

 

// 读取同一目录下的 base config

const config = require('./webpack.base.config');

 

config.module.rules.push(

  {

    test: /\.less$/,

    useExtractTextPlugin.extract(

      {

        use[

          'css-loader',

          'less-loader'

        ],

        fallback'style-loader'

      }

    ),

    exclude: /node_modules/

  }

);

 

config.plugins.push(

  // 官方文档推荐使用下面的插件确保 NODE_ENV

  new webpack.DefinePlugin({

    'process.env.NODE_ENV'JSON.stringify(process.env.NODE_ENV || 'production')

  }),

  // 启动 minify

  new webpack.LoaderOptionsPlugin({ minimizetrue }),

  // 抽取 CSS 文件

  new ExtractTextPlugin({

    filename'[name].css',

    allChunkstrue,

    ignoreOrdertrue

  })

);

 

module.exports = config;


现在在你的工程文件夹里应该已经有三个 Webpack 配置文件,它们分别是:


  • webpack.base.config.js

  • webpack.dev.config.js

  • webpack.config.js


最后,你还需要在 package.json 里添加相应的配置:


{

  ...

  "scripts"{

    "build""webpack --optimize-minimize",

    "dev""webpack-dev-server --config webpack.dev.config.js",

    "start""npm run dev" // 或添加你自己的 start 逻辑

  },

  ...

}


和很多项目一样,在开发环境下的时候,你需要使用 npm run dev 来启动,而在生产环境中,则用 npm run build 来发布。


题外话,在真实场景中,我们不会直接使用 webpack-dev-server,而采用 express + webpack/webpack-dev-middleware,配置方法与上面所述的完全相同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值