https://segmentfault.com/a/1190000006178770
插件(Plugins)是用来拓展webpack功能的,它们会在整个构建过程中生效,执行相关的任务。
Loaders和Plugins常常被弄混,但是他们其实是完全不同的东西,可以这么来说,loaders是在打包构建过程中用来处理源文件的(JSX,Scss,Less...),一次处理一个; 插件并不直接操作单个文件,它直接对整个构建过程起作用。
webpack有很多内置插件,同时也有很多第三方插件,可以让我们完成更加丰富的功能。
要使用某个插件,我们需要通过npm安装它,然后要做的事情就是在webpack配置中的plugins关键字部分添加该插件的一个实例(plugins是一个数据)继续上面的例子,我们添加了一个给打包后代码添加版权声明的插件。
const webpack = require('webpack');
module.exports = {
// ...
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: "babel-loader"
},
exclude: /node_modules/
}, {
test: /\.css$/,
use: [
{
loader: "style-loader"
}, {
loader: "css-loader",
options: {
modules: true
}
}, {
loader: "postcss-loader"
}
]
}
]
},
plugins: [
new webpack.BannerPlugin('Copyright forfan06')
]
}
通过这个插件,打包后的JS文件会有copyright版权声明。
这就是webpack插件的基础用法了, 下面是几个常用的插件:
这个插件的作用是依据一个简单的index.html模板,生成一个自动引用你打包后的js文件的新index.html。这在每次生成的js文件名称不同时非常有用(比如添加了hash值)。
安装
npm install --save-dev html-webpack-plugin
这个插件自动完成了我们之前手动做的一些事情,在正式使用之前需要对一直依赖的项目结构做一些更改:
index.tmpl.html中的模板源代码如下:
Webpack Sample Project
3. 更新webpack的配置文件,方法同上,新建一个build文件夹用来存放最终的输出文件
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: __dirname + '/src/main.js', // 唯一入口文件
output: {
path: __dirname + '/build',
filename: 'bundle.js'
},
devtool: 'eval-source-map',
devServer: {
contentBase: './public', // 本地服务器所加载的页面所在的目录
historyApiFallback: true, // 不跳转
inline: true // 实时刷新
},
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: 'babel-loader'
},
exclude: /node_modules/
}, {
test: /\.css$/,
use: [
{
loader: 'style-loader'
}, {
loader: 'css-loader',
option: {
modules: true
}
}, {
loader: 'postcss-loader'
},
]
}
]
},
plugins: [
new webpack.BannerPlugin('Copyright test'),
new HtmlWebpackPlugin({
template: __dirname + '/src/index.tmpl.html' // new 一个这个插件的实例,并传入相关的参数
})
]
}
再次执行npm start你会发现,build文件夹下面生成了bundle.js和index.html。
Hot Module Replacement(HMR)也是webpack里很有用的一个插件,它允许你在修改组件代码后,自动刷新,实时预览修改后的效果。
在webpack中实现HMR也很简单,只需要做两项配置:
1. 在webpack配置文件中添加HMR插件;
2. 在Webpack Dev Server中添加‘hot’参数;
不过配置完这些后,js模块其实还是不能自动热加载的,还需要再你的js模块中执行一个webpack提供的API才能实现热加载,虽然这个API不难使用,但是如果是React模块,使用我们已经熟悉的Babel可以更加方便的实现功能热加载。
整理下思路,具体实现方法如下:
1. babel和webpack是独立的工具,
2. 二者可以一起工作,
3. 二者都可以通过插件拓展功能,
4. HMR是一个webpack插件,它让你能实现实时观察模块修改后的效果。但是如果你想让它工作,需要对模块进行额外的配置,
5. Babel有一个佳作react-transform-hmr的插件,可以在不对React模块进行额外配置的前提下让HMR正常工作;
通过配置上例来看如何实现热加载
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: __dirname + '/src/main.js', // 入口文件
output: {
path: __dirname + '/build',
filename: 'bundle.js'
},
devtool: 'eval-source-map',
devServer: {
contentBase: './public', // 本地服务器加载页面所在的目录
historyApiFallback: true, // 不跳转
inline: true,
hot: ture
},
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: 'babel-loader'
},
exclude: /node_modules/
},{
test: /\.css$/,
use: [
{
loader: 'style-loader'
},{
loader: 'css-loader',
options: {
modules: true
}
},{
loader: 'postcss-loader'
}
]
}
]
},
plugins: [
new webpack.BannerPlugin('Copyright test'),
new HtmlWebpackPlugin({
template: __dirname + './src/index.tmpl.html' // new一个插件的实例,并传入相关的参数
}),
new webpack.HotModuleReplacementPlugin() // 热加载插件
]
}
安装react-transform-hmr
npm install --save-dev babel-plugin-react-transform react-transform-hmr
配置babel, you can refer this to https://www.npmjs.com/package/react-transform-hmr
// .babelrc
{
"presets": [ "react", "env" ],
"env": {
// only enable it when process.env.NODE_ENV is 'development' or undefined
"development": {
"plugins": [[ "react-transform", {
"transform" [{
"transform": "react-transform-hmr",
// if you use React Native, pass "react-native" instead:
"imports": [ "react" ],
// this is important for Webpack HMR:
"locals": [ "module" ]
}]
// note: you can put more transfor into array
// this is just one of them!
}]]
}
}
}
现在当你使用React时,可以预加载模块了,每次保存就可以在浏览器上看到实时的更新。
目前为止,我们已经使用webpack构建了一个完整的开发环境!!!但是在产品阶段,可能还u要对打包的文件进行额外的处理,比如说优化、压缩、缓存以及分离css和js。
对于复杂的项目来说,需要复杂的配置,这时候分解配置文件为多个小的文件可以使得事情井井有条,以上面的例子来说,我们创建一个webpack.production.config.js的文件,在里面加上借本的配置,它和元素的webpack.config.js很像,如下:
// webpack.production.config.js
const webpack = require('webpack');
const HtmlWebpackPlugin = require('hmlt-webpack-plugin');
module.exports = {
entry: __dirname + '/src/main.js', // 入口文件
output: {
path: __dirname + '/build',
filename: 'bundle.js'
},
devtool: 'eval-source-map',
devServer: {
contentBase: './public', //本地服务器加载页面所在的目录
historyApiFallback: true, // 不跳转
inline: true // 实时刷新
hot: true
},
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: 'babel-loader'
},
exclude: /node_modules/
},{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [{
loader: 'css-loader',
options: {
modules: true
}
}, {
loader: 'postcss-loader'
}]
})
}
]
},
plugins: [
new webpack.BannerPlugin('Copyright test'),
new HtmlWebpackPlugin({
template: __dirname + '/src/index.tmpl.html' // new一个插件的实例,并传入相关参数
}),
new webpack.HotModuleReplacementPlugin() // 热加载插件
]
}
// package.json
{
"name": "test",
"version": "1.0.0",
"description": "This is a test for webpack",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack",
"server": "webpack-dev-server --open",
"build": "NODE_ENV=production webpack --config ./webpack.production.config.js --progress"
},
"author": "forfan06",
"license": "ISC",
"devDependencies": {
// ...
},
"dependencies": {
// ...
"react": "^15.6.1",
"react-dom": "^15.6.1"
}
}
注意如果是window电脑,build需要配置为
"build": "set NODE_ENV=production && webpack --config ./webpack.production.config.js --progress"
webpack提供了一些在发布阶段非常有用的插件,它们大多来自于webpack社区,可以通过npm安装,通过以下插件可以完成铲平发布阶段所需的功能:
1. OccurenceOrderPlugin: 为组件分配ID,通过这个插件webpack可以分析和优先考虑使用最多的模块,并为它们分配最小的ID
2. UglifyJsPlugin: 压缩js代码
3. E下tractTextPlugin:分离css和js文件
其中,OccurenceOrder和UglifyJS plugins都是内置插件,你需要做的只是安装其他非内置插件
npm install --save-dev extract-text-webpack-plugin
在配置文件的plugins后引用它们
// webpack.production.config.js
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: __dirname + '/src/main.js', // 入口文件
output: {
path: __dirname + '/build',
filename: 'bundle.js'
},
devtool: 'eval-source-map',
devServer: {
contentBase: './public',
historyApiFallback: true,
inline: true,
hot: true
},
module: {
rules: [
{
test:/(\.jsx|\.js)$/,
use: {
loader: 'babel-loader'
},
exclude: /node_modules/
},{
test: /.css$/,
use: [
{
loader: 'style-loader'
}, {
loader: 'css-loader',
options: {
modules: true
}
}, {
loader: 'postcss-loader'
}
]
}
]
},
plugins: []
}
此时,执行npm run build可以看见代码是被压缩的。
缓存无处不在,使用缓存的最好方法是保证你的文件名和文件内容是匹配的(内容改变,名称相应的跟着改变)
webpack可以把一个哈希值添加到打包的文件名中,使用方法如下,添加特殊的字符串混合体([name], [id] and [hash])到输出文件名前:
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
// ...
output: {
path: __dirname + '/build',
filename: 'bundles-[hash].js'
},
// ...
}
添加了hash之后,会导致改变文件内容重新打包时,文件名不同而内容越来越多,因此这里需要使用到另外一个插件: clean-webpack-plugin。
安装:
npm install clean-webpack-plugin --save-dev
使用:
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
{
// ...
},
plugins: [
// ... other plugins
new CleanWebpackPlugin('build/*.*', {
root: __dirname,
verbose: true,
dry: false
})
]
}
引入clean-webpack-plugin插件后在配置文件的plugins中做对应配置即可。
关于clean-webpack-plugin的详细使用可参考 https://github.com/johnagan/clean-webpack-plugin