Webpack:从入门到放弃

Webpack:从入门到放弃

参照:Appendix A: Webpack for React

资源:awesome-webpack

webpack前端构建性能优化策略小结

使用NPM安装

全局安装

npm install -g webpack

或,安装为项目开发依赖

npm install --save-dev webpack

初始化项目

  • 创建项目文件夹

  • 运行npm init ,生成package.json 配置文件

  • 为了便于分享项目,最好安装 webpack 为项目依赖:

    npm install --save-dev webpack
  • 项目结构:

    +– webpack-demo

    | +– app

    | `– main.js (或 index.js )

    | `– Greeter.js (模块文件)

    | +– public (或 dist )

    | `– index.html

    `– package.json (项目配置文件)

    `– webpack.config.js (webpack配置文件)

无配置文件webpack.config.js 时

  • 编写 Greeter.js 和 main.js 和 index.html 文件,内容参考 Appendix A: Webpack for React (下同)

  • 运行命令行 :基本格式 : webpack {entry file} {destination for bundled file}

    • 未全局安装 webpack 时:node_modules/.bin/webpack app/main.js public/bundle.js
    • 全局安装 webpack 时:webpack app/main.js public/bundle.js

      自动处理模块依赖并生成 bundle.js文件,打开index.html可浏览

配置文件webpack.config.js

https://github.com/webpack/docs/wiki/configuration

最简配置

  • 最简单的配置文件如下:

    module.exports = {
    4entry: __dirname + "/app/main.js", //or /app/index.js
    4output: {
    44path: __dirname + "/public", //or /dist
    44filename: "bundle.js"
    }

    __dirname是一个 node.js 的全局变量,表示当前所执行的脚本(此处是 webpack.config.js)所在的目录

    entry:可以是字符串、数组、对象。数组时,输出最后一个;对象时(配置输出多个文件),output的filename需要使用[name].js[id].js形式以生成对应的文件

    path:生成文件的本地目录,绝对路径

    publicPath:html 文件中 href 和 src 的引用路径,可以和path一样,也可以不一样,例如 CDN 地址

  • 运行命令:webpacknode_modules/.bin/webpack ,实现与命令webpack app/main.js public/bundle.js 相同的效果

    此时不能再使用webpack app/main.js public/bundle.js 命令,否则会重复生成)

添加任务快捷方式

执行类似node_modules/.bin/webpack 的命令繁琐且容易出错。幸运的是,NPM可以作为任务执行器使用。通过在package.json中的scripts 属性中配置命令,可以简化任务的运行:

{
4"name": "webpack-demo",
4"scripts": {
44"start": "node_modules/.bin/webpack"
4},
4"devDependencies": {
44"webpack": "^2.2.1"
4}
}

然后可以通过npm start命令实现执行node_modules/.bin/webpack 的效果

脚本可以写多个,基本运行语法是: npm run {script name} 上例中是 npm run start (npm startnpm run start在NPM中的简写形式。但最好不用简写形式。不是所有 script 都可以简写?)

详细使用说明参看:npm scripts 使用指南

生成source maps

Webpack 配置中有很多选项,其中最重要和最常用的配置之一就是 source map 配置。

将项目的 js 模块打包到一个单独的 bundle.js 文件给代码在浏览器运行带来许多的优势。但是一个典型的缺陷是,当你在浏览器中debug时,你无法对应到原始的 js 代码文件。你无法确定 bug 存在于哪一个源文件,也就无法确定是谁的代码出现了bug,从而难以修改。 一个 source map 文件提供了一种将打包后的代码映射到源代码文件的途径,使得代码具备可读性且易于调试。

source map 配置使用webpack的devtool属性,其值可以是source-mapcheap-module-source-mapeval-source-mapcheap-module-eval-source-map ,各选项对项目 build 的速度是由慢到快(source-map选项build最慢),但浏览器执行 Javascript 时是由快到慢(source-map选项生成的Javascript代码执行最快)。

对于中小型项目,选择eval-source-map最优

http://webpack.github.io/docs/configuration.html#devtool)

Webpack 开发服务器

Webpack 拥有一个可选的用于本地开发的服务器。其是一个小的node express 应用,提供静态文件服务并根据 Webpack 配置 build 你的资源文件(样式、脚本、html等),将它们驻存到内存中,且当你修改源文件时可以自动刷新浏览器。

此服务器是一个独立的NPM模块,应该安装为项目依赖。

安装命令: npm install --save-dev webpack-dev-server

开发服务器也可以单独的devserver入口配置到项目的webpack.config.js

devserver settingDescription
contentBasewebpack-dev-server 默认为项目根目录下的文件提供服务。如果想要修改服务目录(例如只将public文件夹内的内容加载到服务器。这样其他目录就不能使用dev-server的服务了),需要明确配置此属性
port访问端口,默认“8080”.
inlineSet to “true” to insert a small client entry to the bundle to refresh thepage on change.
colors为服务器运行时的控制台输出着色
historyApiFallbackUseful during the development of single page applications that make use of the HTML5 history API. When set to “true”, all requests tothe webpack-dev-server that do not map to an existing asset will insteadby routed straight to /, that is, the index.html file.

此时的Webpack配置如下:

module.exports = {
devtool: 'eval-source-map',
entry: __dirname + "/app/main.js",
output: {
path: __dirname + "/public",
filename: "bundle.js"
},
devServer: {
contentBase: "./public",
colors: true,
historyApiFallback: true,
inline: true
}
}

运行命令:webpack-dev-servernode_modules/.bin/webpack-dev-server

或者为webpack-dev-serverpackage.json中配置script

> "scripts": {
> "dev": "node_modules/.bin/webpack-dev-server --progress"
> }
>

--progress“ 参数只在命令行中起作用. 它在控制台中显示项目构建步骤

加载器 Loader

loader 是 Webpack 的核心概念之一。Webpack 本身只能处理 JavaScript 模块,如果要处理其他类型的文件,或者将当前浏览器不支持的Javascript 版本(如ES6)代码转换为支持版本的代码,就需要使用 loader 进行转换。Loader 可以理解为是模块和资源的转换器,它本身是一个函数,接受源文件作为参数,返回转换的结果。这样,我们就可以通过 require 来加载任何类型的模块或文件,比如 CoffeeScript、 JSX、 LESS 或图片。

官方文档:https://webpack.js.org/concepts/loaders/

中文:http://webpackdoc.com/loader.html

Loaders 需要独立安装且配置在webpack.config.jsmodule属性之下。loader的配置包括:

  • test: 正则表达式,匹配需用此loader处理的文件的扩展名 (Required).
  • loader: loader 的名称。旧版本可以省略-loader,如coffee-loader可以简写为coffee。但最新版本要求全称,不能省略 (Required).
  • include / exclude: 指定包含或排除的文件夹/文件,Optional
  • query: 给loader传递额外的设置选项

安装loader:npm install --save-dev css-loader

配置loader实例:

module: {
// loaders是一个数组,每个元素都用来指定loader
loaders: [{
test: /\.jade$/, //test值为正则表达式,当文件路径匹配时启用
loader: 'jade-loader', //指定使用什么loader,可以用字符串,也可以用数组
exclude: /regexp/, //可以使用exclude来排除一部分文件
//可以使用query来指定参数,也可以在loader中用和require一样的用法指定参数,如`jade?p1=1`
query: {
p1:'1'
}
},
{
test: /\.css$/,
loader: 'style-loader!css-loader' //loader可以和require用法一样串联
},
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader'] //也可以用数组指定loader
}]
}

官网最新推荐配置(rules 取代 loaders)

module.exports = {
module: {
rules: [
{test: /\.css$/, use: 'css-loader'},
{test: /\.ts$/, use: 'ts-loader'}
]
}
};

use等价于loader

{test: /\.css$/, loader: 'css-loader'}
// or equivalently
{test: /\.css$/, use: 'css-loader'}
// or equivalently
{test: /\.css$/, use: {
loader: 'css-loader',
options: {}
}}

或者在require时使用

require('style-loader!css-loader?modules!./styles.css'); ,其中?modulescss-loader的参数,表示激活css modules(模块化css)处理。参数也可以使用JSON格式。

在命令行中指定loader

webpack --module-bind jade --module-bind 'css=style!css'

上述命令指定 jade-loader 处理.jade 文件, style-loadercss-loader 处理.css 文件.

多个Loader串联使用

如上面的loader: 'style-loader!css-loader'require('style-loader!css-loader?modules!./styles.css');

各个loader按从右到左的顺序处理对应的文件,并以! 分隔

插件Plugins

与loaders的区别

loader 处理每个源文件, 每次一个,当他们在Webpack构建过程中被 “loaded” 时.

Plugins 不处理单个文件,而是对整个项目在构建过程中产生影响.

Webpack中既有Webpack内建的插件,也有其他第三方插件。第三方插件在使用之前需要使用NPM安装,并且配置到plugins数组中:

var webpack = require('webpack');
module.exports = {
devtool: 'eval-source-map',
entry: __dirname + "/app/main.js",
output: {... },
module: {
loaders: [
{ test: /\.json$/, loader: "json" },
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel' },
{ test: /\.css$/, loader: 'style!css?modules!postcss' }
]
},
postcss: [
require('autoprefixer')
],
plugins: [
new webpack.BannerPlugin("Copyright Flying Unicorns inc.") //在生成文件开头插入banner
],
devServer: {... }
}

注意: 新的webpack版本中,不能直接包含自定义配置项,需要配置到webpack.LoaderOptionsPlugin

https://segmentfault.com/q/1010000006987956

plugins: {
new webpack.LoaderOptionsPlugin({
options: {
postcss: function () {
return [precss, autoprefixer];
},
devServer: {
contentBase: "./public", //本地服务器所加载的页面所在的目录
colors: true, //终端中输出结果为彩色
historyApiFallback: true, //不跳转
inline: true //实时刷新
}
}
})
}

模块热替换Hot Module Replacement

Hot Module Replacement(HMR)使得在你修改资源文件之后,浏览器能够自动反映修改效果而无需刷新页面。

两处配置:

  1. 添加 HotModuleReplacementPlugin 配置
  2. 在 Webpack Dev Server 配置中添加 “hot” 参数
// var webpack = require('webpack');
plugins: [
new webpack.HotModuleReplacementPlugin()
],
devServer: {
colors: true,
historyApiFallback: true,
inline: true,
hot: true
}

但对于 JavaScript modules 不能自动适合热替换处理(won’t be automatically eligible for hot replacement.)。

要使JavaScript modules适用于热替换,一种方式是在js模块文件中实现 Webpack 提供的 API.

另一种更实用的方式是: Using Babel.

生产环境/产品环境配置

生产环境通常比开发环境多一些额外的需求,如 优化、压缩、缓存 以及 分离css和js文件等。

上述配置中,所有配置选项都在一个单独的webpack.config.js中。为了更好地组织项目资源和更清晰的区分生产和开发环境,通常将二者的配置分离,单独形成一个webpack.prod.config.js

webpack.prod.config.jswebpack.config.js相比,不需要配置devtool, devServer 和 Hot Module Replacement 等开发时才需要的内容。

而在package.json文件中,我们需要添加一个script:

"scripts": {
4"start": "node_modules/.bin/webpack-dev-server --progress",
4"build": "NODE_ENV=production node_modules/.bin/webpack –config ./webpack.production.config.js --progress"
},

但如果我们在“start” 中也添加 NODE_ENV=development 的话,Windows下可能报错,此时可以使用cross-env 解决跨平台设置NODE_ENV的问题。

使用cross-env解决跨平台设置NODE_ENV的问题

此时的配置为(注意先安装 :npm i cross-env --save-dev ):

"scripts": {
4"start": "cross-env NODE_ENV=development node_modules/.bin/webpack-dev-server --progress",
4"build": "cross-env NODE_ENV=production node_modules/.bin/webpack –config ./webpack.production.config.js --progress"
},

如果不分开两个配置,可以参考如下配置(使用vue-cli生成)

package.json

"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server --inline --open --hot",
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
},

webpack.config.js

//module.exports = {} 之后。module.exports = {} 中按照开发环境配置
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}

生产环境常用插件:

  • UglifyJsPlugin – js文件压缩
  • ExtractTextPlugin 将requires/imports的css单独输出为css文件,从而将其从js文件中抽离

使用:

  1. 首先安装npm install --save-dev extract-text-webpack-plugin
  2. 修改webpack.prod.config.js配置:
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
//in rules or loaders
{
4test: /\.css$/,
4loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules!postcss')
},
{
test: /\.less$/,
loader: ExtractTextPlugin.extract('css-loader!less-loader')
}
//plugins
plugins: [
4new webpack.optimize.OccurenceOrderPlugin(),
4new webpack.optimize.UglifyJsPlugin(),
4new ExtractTextPlugin("style.css") //提取为style.css文件
]

缓存

一个简单有效的缓存方法是,使用基于内容的唯一的文件名。当文件内容发生改变时,文件名相应地发生改变,这样远程客户端会保留一份内容的副本而只去请求发生变化的内容(新的文件名的内容)。

只需简单配置,Webpack 就可以在生成的文件名中添加 hash 值

output: {
4path: __dirname + "/build",
4filename: "[name]-[hash].js"
},
//in plugins
new ExtractTextPlugin("[name]-[hash].css")

或者使用插件

http://www.cnblogs.com/yangmin01/p/6290595.html

// 该插件是对“webpack-md5-hash”的改进:在主文件中获取到各异步模块的hash值,然后将这些hash值与主文件的代码内容一同作为计算hash的参数,这样就能保证主文件的hash值会跟随异步模块的修改而修改。
var WebpackSplitHash = require('webpack-split-hash');
//在 output 中
//以文件内容的MD5生成Hash名称的script来防止缓存
filename: 'js/[name].[chunkhash:8].js',
//异步加载的模块是要以文件形式加载,生成的文件名是以chunkFilename配置的
chunkFilename: 'js/[name].[chunkhash:8].js'
文章目录
  1. 1. Webpack:从入门到放弃
    1. 1.1. 使用NPM安装
    2. 1.2. 初始化项目
    3. 1.3. 无配置文件webpack.config.js 时
    4. 1.4. 配置文件webpack.config.js
      1. 1.4.1. 最简配置
      2. 1.4.2. 添加任务快捷方式
      3. 1.4.3. 生成source maps
      4. 1.4.4. Webpack 开发服务器
      5. 1.4.5. 加载器 Loader
        1. 1.4.5.1. 配置loader实例:
        2. 1.4.5.2. 官网最新推荐配置(rules 取代 loaders)
        3. 1.4.5.3. 或者在require时使用
        4. 1.4.5.4. 在命令行中指定loader
        5. 1.4.5.5. 多个Loader串联使用
      6. 1.4.6. 插件Plugins
      7. 1.4.7. 模块热替换Hot Module Replacement
      8. 1.4.8. 生产环境/产品环境配置
      9. 1.4.9. 缓存
|