0 前言

本文是针对TCM项目所做的WebPack配置文件总结,主要概述了一些常用配置选项和插件使用,对以后的项目有指导意义。
TCM的webpack配置文件包括webapck.config.base.js、webapck.config.dev.js、webapck.config.prod.js三个基本文件, webpack.config.base.js是基本配置文件,webpack.config.dev.js是开发配置,webpack.config.prod.js是产品配置文件,webpack.config.base.js包含一些webpack.config.prod.js和webpack.config.base.js共有的基本配置,而webpack.config.prod.js和webpack.config.base.js在webpack.config.base.js的基础上添加了一些必要配置。为了引入Node的express API,通过dev.js和prod.js对顶层配置进行定义,因此,package.json文件的scripts部分定义了采用不同配置进行开发的npm指令:
图片描述

以下较多内容是对《入门Webpack,看这篇就够了》做的总结,加入很多网上收集的资料,目的是为了更深的了解TCM中的WebPack配置。

1 为什么用webpack?

Node.js的发展使各种依赖广泛涌现,这些依赖包含各种插件、加载器,可以简化开发流程。模块化是前端发展的一大趋势,基于React的单页应用完美诠释了模块化的概念,通过组件的方式进行开发,组件之间互相引用,并且引用外部依赖。为了打包外部依赖以及本地JavaScript模块、SCSS模块、图片等,打包工具应运而生,以WebPack最为著名,类似的还有Gulp/Grunt等。webpack的优点之一就是把所有文件,包括CSS、HTML、图片、JavaScript代码等都视为模块处理,只要配置中包含相应的loader就可以进行处理打包。

1.1 WebPack和Grunt以及Gulp相比有什么特性?

其实Webpack和另外两个并没有太多的可比性,Gulp/Grunt是一种能够优化前端的开发流程的工具,而WebPack是一种模块化的解决方案,不过Webpack的优点使得Webpack可以替代Gulp/Grunt类的工具。
Grunt和Gulp的工作方式是:在一个配置文件中,指明对某些文件进行类似编译,组合,压缩等任务的具体步骤,这个工具之后可以自动替你完成这些任务。
图片描述

Webpack的工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个浏览器可识别的JavaScript文件。
图片描述

2 webpack配置文件常用配置项

webpack有一个默认的配置文件webpack.config.js(官方文档),位于项目根目录,也可以根据需要创建多个配置文件,TCMngr配置了三个文件:webpack.base.conf.js/webpack.dev.config.js/webpack.prod.conf.js。在package.json的scripts中添加不同的命令设置不同的配置文件,在TCMngr的package.json中有

  "scripts": {
    "start": "cross-env NODE_ENV=development node build/dev.js",
    "build": "cross-env NODE_ENV=production node build/prod.js"
  },

可以看到此处使用了cross-env依赖包,这个包允许以UNIX的方式设置环境变量,并在windows上正常运行。安装命令:

    npm install cross-env --save-dev

webpack配置文件本质就是一个JavaScript module,可以使用JavaScript语言,文件会导出一个配置对象,格式如下:

mudule.exports = {};

所有的配置信息都在这个对象中体现,包括:
entry:打包的入口文件,可以使一个字符串或一个对象,如果只有一个需要打包的模块,使用这种形式;如果是一个对象,对象对应的所有文件都被打包,该对象可以是包含多个打包模块的数组,依赖较强的排在前面,也可以是键值对,分别对应不同的输出包,包名就是键名;TCM的webpack.base.conf.js指出了需要打包的文件,包含框架、类库以及入口源码。
图片描述

resolve:影响模块解析的设置,是一个对象,包含以下属性。

resolve.extensions:自动识别的文件扩展名,如果你想请求一个js文件但是在请求时不带扩展        
(如:require('index')),那么就需要将'.js'添加到数组中。并不是必须配置这一选项,不配
置时会使用默认值["", ".webpack.js", ".web.js", ".js"],手动设置会导致默认值被覆
盖。如果想要每个模块都能按照自己的扩展名解析,要加上空字符串。
resolve.modulesDirectories:目录名组成的数组,会在该目录以及该目录的顶层目录寻找依赖
模块,默认值是Default: ["web_modules", "node_modules"]。
resolve.root:包含依赖模块的绝对路径,可能是目录数组

图片描述

resolveLoader:设置和resolve设置类似,只不过是针对loaders设置。
图片描述

output:打包的输出结果,是一个对象,包含以下属性:

filename:输出文件名,filename里面的[name]会由entry中的键替换;
path:输出路径;
publicpath:通过浏览器访问时的公共URL地址。

图片描述

module:定义对模块的处理逻辑,是一个对象;
loaders:定义一系列自动加载的loader,是一个对象数组;

    [
        {
            test:正则表达式,用于匹配处理的文件
            loader/loaders:字符串或数组,表示用到的加载器,loader:string表示用!分隔的loader,loaders:[]表示用到的加载器数组。
            include:包含的文件夹
            exclude:排除的文件夹
        }
    ]

plugins:定义插件,一个数组,定义所有用到的插件。
图片描述

externals:当我们想在项目中require一些其他的类库或者API,而又不想让这些类库的源码被打包时,这在实际开发中很有必要。此时我们就可以通过配置externals参数来解决这个问题:
图片描述

这样我们就可以放心的在项目中使用这些API了:var jQuery = require(“jquery”);

devtool:选择调试工具,常用eval-source-map

//实例
{
    devtool: "#inline-source-map"
}

3 插件(Plugins)和一些工具包

插件(Plugins)是用来拓展Webpack功能的,它们会在整个构建过程中生效,执行相关的任务。Loaders和Plugins常常被弄混,但是他们其实是完全不同的东西,可以这么来说,loaders是在打包构建过程中用来处理源文件的(JSX,Scss,Less..),一次处理一个,插件并不直接操作单个文件,它直接对整个构建过程其作用。要使用某个插件,我们需要通过npm安装它,然后要做的就是在webpack配置中的plugins关键字部分添加该插件的一个实例(plugins是一个数组)。

3.1 webpack-dev-server

一般安装在devDependency中:
npm install webpack-dev-server --save-dev
安装后使用webpack-dev-server即可在浏览器窗口观察输出,浏览器会自动打开项目根目录的index.html文件,默认端口号是8080,完整地址是http://localhost:8080/。使用命令webpack-dev-server --hot --inline完成自动刷新,为了简写命令,在package.json的scripts中添加如下语句:

“build” : “webpack-dev-server --hot --inline --config ‘webpack-dev-config.js’”

--config设置默认的webpack配置文件。
devserver作为webpack配置选项中的一项,具有以下配置选项
图片描述

在webpack.config.js中体现为:

devServer: {
    contentBase: "./public",//本地服务器所加载的页面所在的目录
    colors: true,//终端中输出结果为彩色
    historyApiFallback: true,//不跳转
    inline: true//实时刷新
  }

3.2 Source Maps(使调试更容易)

WebPack生成source maps,可以对应编译文件和源文件,使得编译后的代码可读性更高,更容易调试。配置source maps,需要配置devtool,它有以下四种不同的配置选项,各具优缺点,描述如下:
图片描述

上述选项由上到下打包速度越来越快,不过同时也具有越来越多的负面作用,较快的构建速度的后果就是对打包后的文件的的执行有一定影响。

在学习阶段以及在小到中性的项目上,eval-source-map是一个很好的选项,不过记得只在开发阶段使用它,如下配置

module.exports = {
  devtool: 'eval-source-map',//配置生成Source Maps,选择合适的选项
  entry:  __dirname + "/app/main.js",
  output: {
    path: __dirname + "/public",
    filename: "bundle.js"
  }
}

3.3 Babel:编译ES6和JSX

Babel工具包括babel-core/babel-loader/babel-preset-es2015/babel-preset-react,如果使用命令行还要安装babel-cli。
Babel的配置较为复杂,反映在webpack.config.js与.babelrc中,webpack.config.js会自动调用.babelrc中的配置选项。webpack.config.json会包含以下配置

//webpack.config.js
{
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel'
      }

//.babelrc
{
  "presets": ["react", "es2015"]
}

3.4 CSS-loader

webpack提供两个工具处理样式表,css-loader 和 style-loader,二者处理的任务不同,css-loader使你能够使用类似@import 和 url(...)的方法实现 require()的功能,style-loader将所有的计算后的样式加入页面中,二者组合在一起使你能够把样式表嵌入webpack打包后的JS文件中。
Sass 和 Less之类的预处理器是对原生CSS的拓展,它们允许你使用类似于variables, nesting, mixins, inheritance等不存在于CSS中的特性来写CSS,CSS预处理器可以这些特殊类型的语句转化为浏览器可识别的CSS语句,在webpack里使用相关loaders进行配置就可以使用了,常用的CSS 处理loaders包括Less Loader、Sass Loader、Stylus Loader。

// TCM中开发环境下直接内嵌 CSS 以支持热替换
// autoprefixer自动添加前缀的插件
config.module.loaders.push({
  test: /\.css$/,
  loader: 'style!css!autoprefixer'
}, {
  test: /\.less$/,
  loader: 'style!css!less!autoprefixer'
}, {
  test: /\.scss$/,
  loader: 'style!css!sass!autoprefixer'
});

3.5 浏览器实时同步插件

var   BrowserSyncPlugin = require('browser-sync-webpack-plugin');
config.plugins.push(
  new BrowserSyncPlugin({
    host: '127.0.0.1',
    port: 9090,// 浏览器监听地址
    proxy: 'http://127.0.0.1:9000/',
    logConnections: false,
    notify: false
  }, {
    reload: false
  })
);

3.6 webpack的进度条插件

使用该插件需要在webpack配置中增加以下声明:

var NyanProgressPlugin = require('nyan-progress-webpack-plugin');
plugins: [
  new NyanProgressPlugin()  
]

效果如下:
图片描述

3.7 HtmlWebpackPlugin:自动生成HTML插件

这个插件的作用是依据一个简单的模板,帮你生成最终的Html5文件,这个文件中自动引用了你打包后的JS文件。每次编译都在文件名中插入一个不同的哈希值。

//安装
npm install --save-dev html-webpack-plugin
//webpack.config.js
var HtmlWebpackPlugin = require('html-webpack-plugin');
config.plugins.push(
new HtmlWebpackPlugin({
    filename: 'index.html',
    template: config.commonPath.indexHTML, //载入文件
    chunksSortMode: 'auto'
  })
);

该插件的设置参数很多:
title: 设置title的名字
filename: 设置这个html的文件名
template:要使用的模块的路径
inject: 把模板注入到哪个标签后 'body',
favicon: 给html添加一个favicon './images/favico.ico',
minify:是否压缩 {...} | false
hash:是否hash化 true false ,
cache:是否缓存,
showErrors:是否显示错误,
chunks:目前没太明白
xhtml:是否自动毕业标签 默认false

3.8 Hot Module Replacement

Hot Module Replacement(HMR)也是webpack里很有用的一个插件,它允许你在修改组件代码后,自动刷新实时预览修改后的效果。在webpack中实现HMR也很简单,只需要做两项配置:在webpack配置文件中添加HMR插件;在Webpack Dev Server中添加“hot”参数。不过配置完这些后,JS模块其实还是不能自动热加载的,还需要在你的JS模块中执行一个Webpack提供的API才能实现热加载,虽然这个API不难使用,但是如果是React模块,使用我们已经熟悉的Babel可以更方便的实现功能热加载。Babel有一个叫做react-transform-hrm的插件,可以在不对React模块进行额外的配置的前提下让HMR正常工作。

//webpack中的配置
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
config.plugins.push(
plugins: [
    new webpack.HotModuleReplacementPlugin()//热加载插件
  ]
);

//安装react-transform-hmr
npm install --save-dev babel-plugin-react-transform react-transform-hmr
//Babel中的配置
{
  "presets": ["react", "es2015"],
  "env": {
    "development": {
    "plugins": [["react-transform", {
       "transforms": [{
         "transform": "react-transform-hmr",
         "imports": ["react"],
         "locals": ["module"]
       }]
     }]]
    }
  }
}

3.9 优化插件

OccurenceOrderPlugin :为组件分配ID,通过这个插件webpack可以分析和优先考虑使用最多的模块,并为它们分配最小的ID
UglifyJsPlugin:压缩JS代码;
ExtractTextPlugin:分离CSS和JS文件


zhangding
358 声望23 粉丝

JavaScript+React+Redux