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

在知乎上我们常常会看到有同学发问:BAT 等大型网站的前端工程是如何组织管理的?这的确是一个可以发散的很广的 Q&A,我想如果要我回答这个问题,不如先从 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 = {
 context: SRC_PATH, // 设置源代码的默认根路径
 resolve: {
  extensions: ['.js', '.jsx'] // 同时支持 js 和 jsx
 },
 entry: {
  // 注意 entry 中的路径都是相对于 SRC_PATH 的路径
  vendor: './vendor',
  a: ['./entry-a'],
  b: ['./entry-b'],
  c: ['./entry-c']
 },
 output: {
  path: ASSETS_BUILD_PATH,
  publicPath: ASSETS_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:
      {
       limit: 8192,
       name: 'images/[name].[ext]'
      }
     }
    ]
   },
   {
    test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
    use:
    [
     {
      loader: 'url-loader',
      options:
      {
       limit: 8192,
       mimetype: 'application/font-woff',
       name: 'fonts/[name].[ext]'
      }
     }
    ]
   },
   {
    test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
    use:
    [
     {
      loader: 'file-loader',
      options:
      {
       limit: 8192,
       mimetype: 'application/font-woff',
       name: 'fonts/[name].[ext]'
      }
     }
    ]
   }
  ]
 },
 plugins: [
  // 每次打包前,先清空原来目录中的内容
  new CleanWebpackPlugin([ASSETS_BUILD_PATH], { verbose: false }),
  // 启用 CommonChunkPlugin
  new webpack.optimize.CommonsChunkPlugin({
   names: 'vendor',
   minChunks: Infinity
  })
 ]
};

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: './',
 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$/,
  use: ExtractTextPlugin.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({ minimize: true }),
 // 抽取 CSS 文件
 new ExtractTextPlugin({
  filename: '[name].css',
  allChunks: true,
  ignoreOrder: true
 })
);
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,配置方法与上面所述的完全相同。

关于专栏

如果你喜欢这篇文章,就请关注我的专栏《前端零栈》在这里我们一起聊一聊前端技术和前端工程。

关于作者

Henry,10 岁开始学习计算机编程,高二暑假获得江苏省青少年信息奥林匹克一等奖。2000 年开始自学 JavaScript 及网页制作,2006 年起正式开始从事前端开发工作,从此一干就是 10 多年。加入阿里巴巴前,曾在 SAP 中国研究院担任智慧交通大数据产品经理。

Github:MagicCube (Henry Li)

 小结

前端从开发到部署前都离不开 Webpack 的参与,本文结合了我们自己在开发中碰到的种种问题解决方案,同时借鉴了很多开源项目的配置来介绍一种用 3 个 JS 文件来配置 Webpack 的方法。关于本文如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • webpack+vue.js快速入门教程

    前言 vuejs--轻量.学习成本低.双向绑定.无dom的操作.组件的形式编写 vuejs是个轻量级的mvvm框架, 集合了angular的基本功能,却又比angular更为精简,功能上涵盖了双向绑定.指令.逻辑控制.过滤器.事件监听.函数等.框架的特点使得项目 在状态变更.分页的场景下可以拥有很大的便利--所有的操作只需要变更数组,没有任何的dom操作. webpack--CommonJS的引用和编写方式.loader非常的丰富,包括vue-loader.css-loader.less-loa

  • Webpack 实现 AngularJS 的延迟加载

    随着你的单页应用扩大,其下载时间也越来越长.这对提高用户体验不会有好处(提示:但用户体验正是我们开发单页应用的原因).更多的代码意味着更大的文件,直到代码压缩已经不能满足你的需求,你唯一能为你的用户做的就是不要再让他一次性下载整个应用.这时,延迟加载就派上用场了.不同于一次性下载所有文件,而是让用户只下载他现在需要的文件. 所以.如何让你的应用程序实现延迟加载?它基本上是分成两件事情.把你的模块拆分成小块,并实施一些机制,允许按需加载这些块.听起来似乎有很多工作量,不是吗?如果你使用 Webpa

  • webpack+vue.js实现组件化详解

    简介 在vue中实现组件化用到了vue特有的文件格式.vue,在每一个.vue文件就是一个组件,在组件中我们将html,css,js全部写入,然后在webpack中配置vue-loader就可以了. 建立vue组件 在src目录下建立components文件夹,并在其中建立app.vue文件,这样我们项目的目录结构如下: |--dist //webpack打包后生成的文件夹 | |--build.js |--node_modules //项目的依赖所在的文件夹 |--src //文件入口 | |

  • Vue.js中用webpack合并打包多个组件并实现按需加载

    前言 随着移动设备的升级.网络速度的提高,用户对于web应用的要求越来越高,web应用要提供的功能越来越.功能的增加导致的最直观的后果就是资源文件越来越大.为了维护越来越庞大的客户端代码,提出了模块化的概念来组织代码.webpack作为一种模块化打包工具,随着react的流行也越来越流行. 使用 Vue 开发项目时,如果要使用其单文件组件特性,必然要使用 webpack 或者 browserify 进行打包,对于大型应用,为了提升加载速度,可以使用 webpack 的 code split 功能

  • 基于vuejs+webpack的日期选择插件

    基于vuejs+webpack环境使用的日期选择插件,希望大家喜欢. 支持单选和多选日期 支持限定开始和结束日期范围选择. 支持小时分钟 需要引入fontawesome.io 的图标库. Options :show 是否显示 :type date|datetime :value 默认值 :begin 可选开始时间 :end 可选结束时间 :x 显示x坐标 :y 显示y坐标 :range 是否多选 test.vue <template> <input type="text&quo

  • Webpack 实现 Node.js 代码热替换

    这两天为了这个问题, Gitter 上问, Twitter 上问, GitHub 上问, 两天没反应 原来写博客的 jlongster 不理我, 我也不知道 Webpack 作者的联系方式 最后在 Gitter 上发的消息他似乎看到了, 就粗略地解释了一遍, 醍醐灌顶啊... https://github.com/webpack/docs/issues/45#issuecomment-149793458 Here is the process in short: Compile the serv

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

    在知乎上我们常常会看到有同学发问:BAT 等大型网站的前端工程是如何组织管理的?这的确是一个可以发散的很广的 Q&A,我想如果要我回答这个问题,不如先从 Webpack 配置说起. 时至今日,Webpack 已经成为前端工程必备的基础工具之一,不仅被广泛用于前端工程发布前的打包,还在开发中担当本地前端资源服务器(assets server).模块热更新(hot module replacement).API Proxy 等角色,结合 ESLint 等代码检查工具,还可以实现在对源代码的严格校验检

  • 一次Webpack配置文件的分离实战记录

    前言 随着前端技术的发展,业务逻辑的增多及功能化的繁琐已经成为前端人员最烧脑的问题.前端自动化构建工具的出现,为前端人员带来了项目构建上的福音,成为每个前端工程师必回的技术栈,目前比较流行的Webpack以万物皆模块的思想构建我们的前端项目,同样也是笔者正在使用的一个前端自动化构建工具. Webpack对于每个前端人员来说都不会怎么陌生,它将每一个静态文件当做一个模块,经过一系列的处理为我们整合出最后的需要的js.css.图片.字体等文件. webpack.config.js就是Webpack的

  • webpack配置文件和常用配置项介绍

    1.安装webpack 1.全局安装webpack:npm install webpack -g 或者转化了cnpm则将npm改为cnpm进行安装 2.进行初始化建立package.json文件记录插件,命令行:npm init 3.webpack安装到项目并将写入package.json的devDependencies中, 命令行:npm install webpack --save-dev. 2.webpack配置文件介绍 1.webpack需要配置文件webpack.config.js,手

  • 详解vue2.0脚手架的webpack 配置文件分析

    前言 作为 Vue 的使用者我们对于 vue-cli 都很熟悉,但是对它的 webpack 配置我们可能关注甚少,今天我们为大家带来 vue-cli#2.0 的 webpack 配置分析 vue-cli 的简介.安装我们不在这里赘述,对它还不熟悉的同学可以直接访问 vue-cli 查看 目录结构 . ├── README.md ├── build │ ├── build.js │ ├── check-versions.js │ ├── dev-client.js │ ├── dev-server

  • vue-cli webpack配置文件分析

    相信vue使用者对vue-cli都不会陌生,甚至可以说,很熟悉了,但对其webpack的配置可能知之甚少吧. 过完年回来后,我接手了公司的新项目.新项目是一个spa.很自然,我就想到了vue-cli脚手架了,当时研究一下它的webpack配置.于是,就有了其他的内容. 今天这篇文章,是在原来的基础上,增加了一些新版本的内容,但实质上变化不大. 说明 此仓库为vue-cli webpack的配置分析,其实只是在源码中加上注释而已.大家查看详细分析,可以从后面提到的入口文件开始查看. 分析不包括ch

  • JBoss5.x下配置Log4j方法介绍

    最近在学习JBoss下配置Log4j,JBoss的各个版本的目录.JBoss和Log4j集成的文件名每次都有变化,在JBoss5.x下配置了log4j.xml文件,但是配置没有生效.如果你在项目中没有指定使用的log4j的配置文件,最好使用JBoss自带的配置文件,文件名为jboss-log4j.xml.该文件在Jboss容器的目录为:${JBOSS_HOME}\server\default\conf下.下面就是基于log4j默认配置的一些基本修改和注释: <span style="fon

  • 20170918 前端开发周报之JS前端开发必看

    1.用函数式编程对JavaScript进行断舍离 当从业20的JavaScript老司机学会函数式编程时,他扔掉了90%的特性,也不用面向对象了,最后发现了真爱啊!!! http://www.jb51.net/article/123958.htm 2.JavaScript作用域和闭包 作用域和闭包在JavaScript里非常重要.但是在我最初学习JavaScript的时候,却很难理解.这篇文章会用一些例子帮你理解它们.我们先从作用域开始.作用域 JavaScript的作用域限定了你可以访问哪些变

  • vue-cli的webpack模板项目配置文件分析

    由于最近在vue-cli生成的webpack模板项目的基础上写一个小东西,开发过程中需要改动到build和config里面一些相关的配置,所以刚好趁此机会将所有配置文件看一遍,理一理思路,也便于以后修改配置的时候不会"太折腾". 一.文件结构 本文主要分析开发(dev)和构建(build)两个过程涉及到的文件,故下面文件结构仅列出相应的内容. ├─build │ ├─build.js │ ├─check-versions.js │ ├─dev-client.js │ ├─dev-ser

  • webpack常用配置项配置文件介绍

    一.webpack基础 1.在项目中生成package.json:在项目根目录中输入npm init,根据提示输入相应信息.(也可以不生成package.json文件,但是package.json是很有用的,所有建议生成) 2.安装webpaack a.在全局中安装webpack:npm install webpack -g b.将webpack安装到项目并将webpack写入package.json的devDependencies中:进入项目根目录,然后在命令行中输入npm install w

  • 详解如何使用webpack打包Vue工程

    使用webpack打包Vue工程 前言 入行一年,从什么都不懂的小白,到现在什么都懂一点的小白,也算是飞跃了.感叹一下现在的前端,从nodejs出来到现在各种各样的工具如雨后春笋般的出现.大神们疯狂的造轮子,玩的不亦乐乎.我等小白们,疯狂追赶,学的心肝脾肺都快衰竭.而我的精力也仅限浅尝辄止,但是学多一点总有好处的.本篇文章就是介绍如何使用webpack构建前端工程. 目标 本次的工程以Vue.js为主角,Vue.js是一款小巧优雅而且强大的轻量级mvvm框架,配合webpack模块化打包.制作出

随机推荐