本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
vue、react等框架以及模块化编程让项目更加清晰、更易维护,而对于页面的加载来说,模块文件多就意味着请求数多,网页的加载速度就慢,而各框架通常有自有的语法及文件类型。webpack通过loader去处理非 JavaScript 文件,将模块打包成一个或多个静态资源文件(js、css、jpg|png等等)并进行优化。
一、安装webpack
在项目文件夹路径下,安装webpack和webpack-cli:
npm install webpack webpack-cli --save-dev
使用webpack进行打包是在配置文件中设置的,默认的配置文件webpack.config.js,
也可以在package.json里指定配置文件:(将上图的webpack.config.js改为aa.js)
二、核心概念
1、entry与output
entry指定webpack的打包入口,从入口开始查找依赖,递归形成依赖树,最终遍历这些依赖,生成打包后的文件。
与之对应,output指定webpack 在哪里输出它所创建的打包文件,以及如何命名这些文件。
webpack打包分为单入口和多入口。
单入口。entry为入口文件相对地址的字符串,output为一个对象,有path和filename两个字段。
如下图的配置,打包后将生成一个js文件,dist目录下的bundle.js。
多入口:entry为一个对象,每一个字段为一个入口。output的filename为"[name].js",通过占位符来确保输出的多个js文件与入口js文件一一对应。
如下图的配置,打包后将生成两个js文件(与entry中的入口数量相同),dist目录下的index1.js和test1.js
2、loader
webpack 自身只理解 javascript和json,loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,并添加到依赖图中进行打包处理。loader本身是一个函数,接受源文件作为参数,并返回转换的结果。
loader的配置是在module对象的rules字段。rules是一个数组,可以配置多个loader。每个loader 有两个属性:
test,用于匹配出应该被对应的 loader 进行转换的某个或某些文件,值为正则表达式。
use, 表示应该使用哪个 loader对源文件进行转换。
日常开发中,常用的loader有:
- babel-loader: 转换es6、es7等JS新特性语法
- css-loader: 支持.css文件的加载和解析
- less-loader: 转换less文件成css(类似的有sass-loader/stylus-loader)
- style-loader: 生成一个内容为最终解析完的css代码的style标签,并放到head标签里
- postcss-loader: 进一步处理css文件,比如添加浏览器前缀,压缩css等
- url-loader: 处理图片、字体图标等文件
以css-loader和style-loader为例:
webpack.config.js配置:
module.exports = {
entry: "./src/index.js",
output: {
path: path.join(__dirname,"/dist"),
filename: "bundle.js"
},
module:{
rules:[
{
test: /\.css$/,
use: ['style-loader','css-loader']
}
]
},
}
(1)index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>酷酷酷</div>
<script src="./dist/bundle.js"></script>
</body>
</html>
(2)index.js(css-loader使得在js文件中可以解析css文件,否则会报语法错误)
import "./css/index.css"
(3)index.css
body{
color: red;
}
最终生成的文档结构:(style-loader生成一个内容为最终解析完的css代码的style标签,并放到head标签里,如果没有style-loader生成的style标签,index.css里的样式不会对文档生效)
值得注意的是:一个匹配规则中可以配置使用多个 loader,即一个模块文件可以经过多个 loader 的转换处理,loader执行的顺序是从右往左。
3、plugins
loader对源文件进行预处理,而plugin作用到构建打包的整个过程,比如文件压缩、资源管理等等。
plugin的配置是在plugins数组中,需要使用某个插件就将它添加到plugins数组。
平时用的比较多的plugin有:
- html-webpack-plugin:创建html文件去承载输出的bundle
let HtmlWebpackPlugin = require('html-webpack-plugin');
new HtmlWebpackPlugin({
template: 'index.html', // 用到的模板文件,不局限html后缀
filename: 'index.html', // 生成的html文件命名(位于dist目录下)
hash: true, // 会在打包好的bundle.js或抽离的.css文件后加hash串
inject: true, //是否能注入内容到输入的页面去
minify: {
removeComments: true, //移除HTML中的注释
collapseWhitespace: true, //删除空白符与换行符,整个文件会压成一行
}
})
将会根据1处的index.html生成2处的index.html,并在2的index.html加入bundle.js的引用:
<script src="bundle.js?29a7f233afce83fb4104"></script>
- clean-webpack-plugin: 清理构建目录。可以解决文件hash值输出时dist目录文件不断累积的问题
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
new CleanWebpackPlugin()
- copy-webpack-plugin:拷贝文件或目录,比如static文件夹。
new CopyWebpackPlugin({
patterns: [
{
from: __dirname+'/src/static',
to: __dirname+'/dist/static'
}
]
})
- mini-css-extract-plugin: 将css按模块化解压到单独的文件中,为每个包含css的js文件创键一个css文件。(style-loader 是将css文件以行内样式style的标签写入打包后的html页面;mini-css-extract-plugin是直接link方式引入进去,js文件中若引入多个css文件也将会合并成一个css文件,其中的内容按js文件中的引入顺序)
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module:{
rules:[
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader,'css-loader']
//去掉style-loader,换成MiniCssExtractPlugin.loader
},
]
},
plugins:[
new MiniCssExtractPlugin({
filename: 'style/style.css' //默认为dist目录下的main.css
})
]
- optimize-css-assets-webpack-plugin:压缩css文件,优化css结构
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
new OptimizeCSSAssetsPlugin()
- uglifyjs-webpack-plugin: 压缩js代码。
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
new UglifyJsPlugin({
uglifyOptions: {
compress: {
drop_debugger: true,
drop_console: true, //生产环境自动删除console
}
},
sourceMap: false
})
uglifyjs-webpack-plugin不能压缩es6的代码文件,出现ERROR in bundle.js from UglifyJs Unexpected token: operator «>» ,所以使用该插件需要用babel-loader将es6转换成es5。
mode为production时,会自动开启UglifyJsPlugin。
4、mode
mode用来指定当前的构建环境,有production、development、none三种情况,默认值是production。设置mode可以使用webpack的内置函数,如下。
-
development: 启用 NamedChunksPlugin 和 NamedModulesPlugin。
-
production: 启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin。
-
none: 不开启任何优化选项。
mode可以在配置文件中设置:
module.exports = {
mode: 'development'
};
也可以在命令行设置:
webpack --mode development