本质上,webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。
- 一些准备
全局安装webpack:npm install -g webpack
安装完webpack,命令行执行webpack会报错,这是因为webpack4把命令行工具抽离成了独立的包,webpack-cli,所以还需要安装webpack-cli才能使用webpack命令
安装webpack-cli或webpack-command:npm install -g webpack-cli
或npm install -g webpack-command
查看webpack版本:webpack -v
$ webpack -v
webpack: 5.70.0
webpack-cli: 4.9.2
webpack-dev-server not installed
- 初始化项目:
mkdir test_webpack
cd test_webpack
npm init
开发环境安装webpack以及webpack-cli或webpack-command的依赖
npm install --save-dev webpack
npm install --save-dev webpack-cli
或npm install --save-dev webpack-command
项目下新建src文件夹,新建入口文件app.js,页面文件work.js
项目下新建index.html
项目下新建webpack.config.js,webpack的一些配置写在这里
app.js
var dt = require('./work.js')
work.js
document.write('test-webpack')
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<div>test</div>
<script src='./dist/bundle.js'></script>
</body>
</html>
webpack.config.js
- cache: true 开启缓存功能,只有变化的文件才会重新加载,可提升构建速度
- entry:
单入口:value为相对路径,路径可以为数组(在你想要一次注入多个依赖文件,并且将它们的依赖关系绘制在一个 "chunk" 中时,这种方式就很有用。),这时要注意主入口在最后。简写为
module.exports = {
entry: './path/to/my/entry/file.js',
};
module.exports = {
entry: ['./src/file_1.js', './src/file_2.js'],
output: {
filename: 'bundle.js',
},
};
多入口:有几个入口,webpack就会打几个包(bundle)出来,打出来的包的文件名与key对应。
module.exports = {
entry: {
app: './src/app.js',
adminApp: './src/adminApp.js',
},
};
对象语法会比较繁琐。然而,这是应用程序中定义入口的最可扩展的方式。
有以下几个属性
dependOn
: 当前入口所依赖的入口。它们必须在该入口被加载前被加载。filename
: 指定要输出的文件名称。import
: 启动时需加载的模块。library
: 指定 library 选项,为当前 entry 构建一个 library。runtime
: 运行时 chunk 的名字。如果设置了,就会创建一个新的运行时 chunk。在 webpack 5.43.0 之后可将其设为false
以避免一个新的运行时 chunk。
注意:
1)runtime 和 dependOn 不应在同一个入口上同时使用,配置无效,并且会抛出错误
module.exports = {
entry: {
a2: './a',
b2: {
runtime: 'x2',
dependOn: 'a2',
import: './b',
},
},
};
2)runtime 不能指向已存在的入口名称,会抛出错误
module.exports = {
entry: {
a1: './a',
b1: {
runtime: 'a1',
import: './b',
},
},
};
3)dependOn 不能是循环引用的,会出现错误
module.exports = {
entry: {
a3: {
import: './a',
dependOn: 'b3',
},
b3: {
import: './b',
dependOn: 'a3',
},
},
};
publicPath
: 当该入口的输出文件在浏览器中被引用时,为它们指定一个公共 URL 地址。output:打包之后存放的文件路径。即使可以存在多个
entry
起点,但只能指定一个output
配置。
module.exports = {
output: {
filename: 'bundle.js',
},
};
path
必须是绝对路径,打包后的文件存放的地方, 常取值为:
__dirname+’/build’或path.resolve(__dirname,’build’)(__dirname是node.js里的一个全局变量,它指向的是我们项目的根目录),
filename
为打包后的文件名。对于单入口文件,可以取一个固定的名字,如’build.js’,对于多入口文件,要使用[name].bundle.js或[id].bundle.js来对应,其中name和id是根据多入口文件对象的属性动态确定的
publicPath
规定线上地址,打包后的文件中资源的引用地址会根据这个地址而改变,一般取为’/assets/’
chunkFilename
webpack可以做代码分割,这个属性规定那些做了代码分割的块(chunk)的名字
默认使用 [id].js
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry:{
app:__dirname+'/src/app.js',
},
output:{
path: path.resolve(__dirname, './dist'),
filename:'bundle.js'
}
};
// 写入到硬盘:./dist/app.js, ./dist/search.js
多入口的output,name与entry的key相对应
module.exports = {
entry: {
app: './src/app.js',
search: './src/search.js',
},
output: {
filename: '[name].js',
path: __dirname + '/dist',
},
};
package.json
{
"name": "test_webpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack",
"dev": "webpack --mode development",
"build": "webpack --mode production",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.70.0",
"webpack-cli": "^4.9.2"
}
}
执行npm start
打包,或webpack 生成dist文件夹下bundle.js
--mode 区分环境,有两周可选的模式,
npm run dev
开发环境,命令为 webpack --mode = development
,
npm run build
生产环境,命令为webpack --mode = production
,
开发环境打包出来的文件未经过压缩,而生产环境打包出来的文件是经过压缩的。
可见,生产环境的打包出来的文件bundle.js是188bytes,而开发环境是2.43KiB,生产环境会做一些压缩以提高性能。
查看页面,地址栏输入index.html的路径file:///C:/Users/xxxx/workspace/test_webpack/index.html
- module:
- rules 数组,配置编译规则,
test 正则匹配,exclude 排除特定条件,use-loader,test 匹配到的解析器模块,use-options,与use-loader配合使用。
有时还会有query或options配置,二者都是use:{options}的简写,所以在用了use后就不需要这两个配置了,如下(一个loader对应一个options,使用多个loader时用use):
- rules 数组,配置编译规则,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
importLoaders: 1
}
},
{
loader: 'less-loader',
options: {
noIeCompat: true
}
}
]
- noParser
防止 webpack 解析任何与给定正则表达式相匹配的文件,忽略大型库文件(library)可以提高构建性能
noParse: /jquery|lodash/
plugins:插件。plugins 与 loader 的区别在于,loader 只是一个解析模块,比如将 ES5 解析成 ES6,LESS 文件解析成 CSS 文件,为了兼容浏览器。而 plugins 是将 loader 之后的文件进行优化分类、压缩、提供公共代码等。
devServer:服务器配置,contentBase 文件路径,compress 是否启动 gzip 压缩,host 主机地址,port 端口号,publicPath。
loader
loader 用于对模块的源代码进行转换。webpack只能处理javascript模块,处理其他类型的文件需要loader进行转换。
像处理css文件 需要css-loader和style-loader,
css-loader:遍历css文件找到url()表达式然后处理他们
style-loader:将css代码插入到一个页面中的style标签中
处理ts文件,需要ts-loader将TypeScript 转为 JavaScript
安装css-loader和style-loader:npm install css-loader style-loader
安装ts-loadernpm install ts-loader
注意:loader 从右到左(或从下到上)地取值(evaluate)/执行(execute)。
module.exports = {
module: {
rules: [
{ test: /\.css$/, use: 'css-loader' },
{ test: /\.ts$/, use: 'ts-loader' },
],
},
};
1)loader 支持链式调用。
2)loader 可以是同步的,也可以是异步的。
3)loader 运行在 Node.js 中,并且能够执行任何操作。
4)loader 可以通过 options 对象配置。
5)除了常见的通过 package.json 的 main 来将一个 npm 模块导出为 loader,还可以在 module.rules 中使用 loader 字段直接引用一个模块。
6)插件(plugin)可以为 loader 带来更多特性。
7)loader 能够产生额外的任意文件。
- 常用plugin:
- extract-text-webpack-plugin 与 mini-css-extract-plugin
分离 .css 分解,后者需要 webpack 4.2.0 版本以上。 - UglifyJsPlugin
压缩 js 文件,减小 js 文件。 - html-webpack-plugin 与 html-loader
生成 html 文件。 - clean-webpack-plugin
每次构建之前清理历史打包文件。
CommonsChunkPlugin
DefinePlugin
HtmlWebpackPlugin
UglifyjsWebpackPlugin
ExtractTextWebpackPlugin
OptimizeCSSPlugin
CompressionWebpackPlugin
SourceMapDevToolPlugin
FriendlyErrorsPlugin
BundleAnalyzerPlugin
- resolve
配置模块如何解析- root:字符串或值为字符串的数组,绝对路径,配置alias中依赖项的基地址
- alias
创建 import 或 require 的别名,来确保模块引入变得更简单。
对象,key为变量名,值为路径。key指定的变量将成为全局变量,比如想在任何文件中都是用jquery而不必每次都显示引入,可以这样{$:jquery文件的地址},地址可以是相对地址(相对root指定),也可是绝对地址(使用path.resolve(__dirname,’jquery’)). - extensions:数组,文件扩展名,某文件的扩展名在该数组中时,该文件在引入时可省略扩展名,常取值有[‘’ , ’.js’ , ‘.json’ , ‘.scss’ , ‘.vue’]
- modules
告诉 webpack 解析模块时应该搜索的目录
resolve: {
extensions: ['.js', '.vue', '.json'],
modules: [
resolve('src'), //实际返回了src的路径,会优先于node_modules搜索
resolve('node_modules')
],
alias: {
'vue$': 'vue/dist/vue.common.js',
'@': resolve('src'),
'src': resolve('src'),
'assets': resolve('src/assets'),
'components': resolve('src/components'),
'styles': resolve('src/styles'),
'utils':resolve('src/utils'),
'demos':resolve('src/demos'),
'cnode':resolve('src/cnode')
}
}
- externals
提供了不从 bundle 中引用依赖的方式。也就是所创建的 bundle 依赖于那些存在于用户环境(consumer environment)中的依赖。比如jquery是用script的方式从html引入的,要想在其他模块中引入的时候就可以使用这个配置
// html
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
// 配置
externals: {
$: 'jQuery' //key不加引号,value是脚本里的全局对象,这里value还可以是数组或对象,但表示的含义大不一样,可参看[这里](http://www.css88.com/doc/webpack2/configuration/externals/)
}
// 其他模块引入的方式
import $ from 'jquery';
- performance、stat
performance:某个打包后的包超过给定阈值时给出提示
stat: 控制webpack打包后输出哪些信息
package.json
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry:{
app:__dirname+'/src/app.js',
},
output:{
path: path.resolve(__dirname, './dist'),
filename:'bundle.js'
},
// module: {
// loaders:[
// {test: /\.css$/, loader: "style-loader!css-loader"}
// ],
// plugin: [
// new webpack.BannerPlugin('webpack 实例')
// ]
// }
module:{
rules:[
{
test: /\.js$/,
loader: 'babel-loader?cacheDirectory=true',
include: [
resolve('src'),
],
exclude:path.resolve(__dirname, 'node_modules')
},
{
test:/\.css$/,
use:[
'style-loader',
'css-loader',
'postcss-loader'
]
},{
test:/\.(png|svg|jpg|gif)$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
}
]
}
};
安装webpack-dev-server:npm install webpack-dev-server -g
打开localhost:8080