一、概念
webpack由4个核心概念组成的:
- 入口(entry)
- 输出(output)
- loader
- 插件(plugins)
1、入口(entry)
**** 入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的**。**
通过webpack配置文件中的entry属性可以设置一个或者多个入口文件,默认为.src/index.js
例子:
webpack.config.js //默认的webpack打包配置文件
modules.export = {
entry: './path/to/my/entry/file.js'
}
配置单个入口:
打包形成一个chunk,输出一个bundle文件,默认chunk和bundle名称为main
配置方式由以下几种:
//第一种
modules.export = {
entry: './path/to/my/entry/file.js'
}
//第二种
modules.export = {
entry: {
main:'./path/to/my/entry/file.js'
}
//第三种
modules.export = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
};
//分离 应用程序(app) 和 第三方库(vendor) 入口
多入口配置方式:
1. 数组array:
所有文件最终会形成一个chunk,输出出去的只有 一个bundle文件
modules.export = {
entry: ['./src/app.js','./src/vendors.js']
};
向 entry 属性传入**「文件路径(file path)数组」将创建“多个主入口(multi-main entry)”**。在你想要多个依赖文件一起注入,并且将它们的依赖导向(graph)到一个“chunk”时,传入数组的方式就很有用。
2. 对象object:
有几个文件就形成几个chunk,输出几个bundle文件, 此时chunk的名称为key
//对象
modules.export = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
};
//3 个独立分离的依赖图
注:每个 HTML 文档只使用一个入口起点。
2、出口(output)
output是告诉 **webpack需要将编译好的文件(bundle)输出到什么地方 **去,以及如何命名这些文件。默认是输出到./dist目录下。也可以通过output指定,最终整个程序的编译结果都将输出到你指定的输出路径文件夹下。
你可以通过配置中指定一个 output 字段,来配置这些处理过程:
filename用于输出文件的文件名。- 目标输出目录
path的绝对路径。 publicPath该配置能帮助你为项目中的所有资源指定一个基础路径(用于定义所有资源引入的公共前缀),对于输出CDN资源很有效。chunkFileName: 非入口chunk的名称library: 定义整个库向外暴露的变量名,方便外部调用libraryTarget:配合library使用,library导出的变量名可以通过怎样的方式访问(window|global|commonjs)
webpack.config.js
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'), //指定输出文件夹路径
filename: 'my-first-webpack.bundle.js', //指定输出文件名称
publicPath: '/', //添加公共前缀
chunkFileName: 'js/[name]_chunk.js',
library: [name], //向外暴露的变量名,这样默认为chunk名,
libraryTarget: 'global' //给上面定义的变量的方式,这个代表可以通过global访问变量
//libraryTarget: 'commonjs' //代表可以通过commonjs的方式require引入
}
};
当entry配置多个入口时:
{
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
}
// 写入到硬盘:./dist/app.js, ./dist/search.js
高级用法
//使用 CDN 和资源 hash 的复杂示例
output: {
path: "/home/proj/cdn/assets/[hash]",
publicPath: "http://cdn.example.com/assets/[hash]/"
}
3. loader
在此步骤生成依赖关系图
本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块。
loader两个属性:
-
test属性: 用于标识出应该被对应的 loader 进行转换的某个或某些文件。 -
use属性: 表示进行转换时,应该使用哪个 loader。多个loader使用 -
loader属性: 使用单个loader进行转化时 -
exclude属性: 排除某些文件 -
include属性: 只检查(转换)某个路径下的文件 -
enforce属性: 当定义多个规则对同一种文件进行检查时,可以使用这个属性将某个规则的执行顺序改变。 值为'pre'优先执行, 值为'post'延后执行 -
option属性: 设置loader的某些参数设置,类似于url-loader可以设置option={limit:8*1024}代表此规则对8kb以下的文件使用base64编码.
例:如下定义了一个规则,就是在对require()/import 语句中被解析为 '.txt' 的路径文件,先使用raw-loader进行 转换一下。.css结尾的路径使用css-loader转换, .ts结尾的使用ts-loader转化。
const path = require('path');
const config = {
output: {
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{
test: /\.txt$/,
loader: 'raw-loader',
exclude: /node_modules/, //排除node_modules下面的模块
include: resolve(_dirname, 'src'), //只检查src路径下的文件
enforce: 'pre', //当定义多个规则对同一种文件进行检查时,可以使用这个属性将某个规则的执行顺序改变
},
{ test: /\.css$/, use: ['style-loader','css-loader'] },
{ test: /\.ts$/, use: 'ts-loader' },
{ test: /\.(png|jpg|gif)$/, loader: 'url-loader', option:{ limit: 8*1024}}
]
}
};
module.exports = config;
注:loader 支持链式传递。能够对资源使用流水线(pipeline)。一组链式的 loader 将按照相反的顺序执行。loader 链中的第一个 loader 返回值给下一个 loader。在最后一个 loader,返回 webpack 所预期的 JavaScript。
loader中的use数组执行顺序:从右到左,从下到上,依次执行,上一个loader的返回值给下一个loader继续执行,最后一个返回给webpack
例: 先 sass-loader 再 css-loader 再 style-loader
module.exports = {
module: {
rules: [
{
// 增加对 SCSS 文件的支持
test: /\.scss/,
// SCSS 文件的处理顺序为先 sass-loader 再 css-loader 再 style-loader
use: [
'style-loader',
{
loader:'css-loader',
// 给 css-loader 传入配置项
options:{
minimize:true,
}
},
'sass-loader'],
},
]
},
};
例:
module.exports = {
module: {
rules: [
{
// 增加对 CSS 文件的支持
test: /\.css/,
// use数组中的loader执行顺序:从右到左,从上到下,依次执行
use: [
'style-loader', //创建style标签,将js中的样式资源添加到style标签中,然后放入head中生效
'css-loader' //将import/require的css文件加载到js模块中。
],
},
]
},
};
4.插件(plugins)
plugins主要是webpack的扩展功能,就是当loader转化过后,可以通过plugins对转化后的模块进行再加工处理,例如打包,压缩等。
通过 require() 引入插件,然后把它添加到 plugins 数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 **new** 操作符来创建它的一个实例。
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件
const config = {
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
},
plugins: [
new HtmlWebpackPlugin({template: './src/index.html'})
//使用HtmlWebpackPlugin将输出后的bundle输出到index.html中
]
};
module.exports = config;
5.模式(Mode)
development 或 production 之中的一个来启用相应模式下的 webpack 内置的优化。
module.exports = {
mode: 'production'
};
或者从 CLI 参数中传递:
webpack --mode=production
6. resolve解析模块的规则
有以下几个属性:
alias: 创建import或require的别名,来确保模块引入变得更简单。优点:可以简写路径,缺点:写路径时没有提示。
例:当文件想访问某个路径比较长的文件时,可以采取别名的方式
webpac.config.js
//假设目录是:
-src
-utilities
-utilities.js -templates
-templates.js -js
-index.js
-css
-index.css
Utilities: path.resolve(__dirname, 'src/utilities/'),
Templates: path.resolve(__dirname, 'src/templates/')
webpac.config.js
//-----start----//
var { resolve } = require('path');
module.exports = {
//
reslove:{
alias: {
$css: resolve(_dirname, 'src/css'), //意思是给src/css路径命别名,
Utilities: path.resolve(__dirname, 'src/utilities/'),
Utilities: path.resolve(__dirname, 'src/templates/')
}
}
}
//-----end-----//
index.js
//-----start-----//
import '../css/index.css';
import '../utilities/utility';
import '../templates/templates';
//可以换成下面
import '$css/index.css'; //因为经过webpack给路径弄了别名
import 'Utilities/utility.js';import 'Utilities/templates.js';
-
extensions: 配置省略文件路径的后缀名(自动解析确定的扩展)。对省略文件后缀的路径会按照数组中从左到右的补全后缀进行匹配,当都没有匹配到,就会报错 。默认值为:extensions: [".js", ".json"]
使用此选项,会覆盖默认数组,这就意味着 webpack 将不再尝试使用默认扩展来解析模块。对于使用其扩展导入的模块,例如,
import SomeFile from "./somefile.ext",要想正确的解析,一个包含“*”的字符串必须包含在数组中。
module.exports = {
reslove:{ alias: {
$css: resolve(_dirname, 'src/css'), //意思是给src/css路径命别名,
Utilities: path.resolve(__dirname, 'src/utilities/'),
Utilities: path.resolve(__dirname, 'src/templates/')
},
//从左到右添加后缀匹配,匹配成功则不会往后匹配
extensions: ['.js', 'json', '.jsx', '*']
} }
-
modules:告诉 webpack 解析模块时应该搜索的目录。默认是modules:['node_modules']
如果你想要添加一个目录到模块搜索目录,此目录优先于 node_modules/ 搜索:
modules: [path.resolve(__dirname, "src"), "node_modules"]
7、devServer配置
用于开发环境的配置,有以下几个属性:
module.exports = {
devServer: {
//运行代码的目录
contentBase: resolve(_dirname, 'build'),
//监视文件comtentBase目录下的文件,一旦文件变化就会重载
watchContentBase: true,
watchOptions: {
//忽略文件,不监视node_modules文件
ignored: /node_modules/
}
//启动gzip压缩
compress: true,
//端口号
port: 5000
//域名
host: 'localhost',
//自动打开浏览器
open:true,
//开起HMR功能
hot:true,
//不要显示启动服务器的日志信息
clientLogLevel: 'none',
//除了基本启动信息以外,其他信息都不要打印
quiet: true,
//如果出错了,不要进行全屏提示
overlay: false,
//服务器代理:解决开发环境跨域问题
proxy: {
//当服务器访问监视到/api开头的请求,将请求转发到配置的地址
'/api': {
target: 'http://localhost:3000',
//发送请求是,请求路径重写:将/api/***--->/***
pathRewrite: {
'^/api': ''
}
},
//默认情况下,不接受运行在 HTTPS 上,且使用了无效证书的后端服务器。
//如果你想要接受,设置secure:false
"/test": {
target: "https://other-server.example.com",
secure: false
}
}
}
}
8. externals:配置选项提供了「从输出的 bundle 中排除依赖」的方法
例如,从 CDN 引入 jQuery,而不是把它打包:
webpack.config.js
externals: {
jquery: 'jQuery'
}
这样就剥离了那些不需要改动的依赖模块,换句话,下面展示的代码还可以正常运行:
import $ from 'jquery';
$('.my-element').animate(...);
index.html
<script
src="https://code.jquery.com/jquery-3.1.0.js"
integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
crossorigin="anonymous">
</script>
9、optimization:代码分割
有以下几个属性::
module.exports = {
optimization: {
splitChunks:{
chunks: 'all',
//以下是默认值,可以不写
minSize: 30*1024, //分割chunk最小为30kb,
maxSize:0, //最大没有限制,
minChunks: 1,//要提取的chunk最少被引用过一次
maxAsyncRequests:3, //按需加载时并行加载文件的最大数量
minInitialRequests:3, //入口js文件最大并行请求数量
automaticNameDelimiter: '~',//名称连接符
name: true, //可以使用命名规则
cacheGroups: {
//分割chunk数组
//node_modules文件会被打包到vendors组的chunk中, ---verndors~xxx.js
//满足上面的公共规则,如:大小超过30kb,至少被引用一次
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10 //优先级
},
default: {
minChunks: 2, //要提取的chunk最少被引用多少次
priority: -20, //优先级
//如果当前打包的模块和之前已经被提取的模块是同一个,就会复用,而不是重新打包
reuseExistingChunk: true
}
}
},
//将当前模块记录在其他模块的hash值单独打包为一个文件runtime.js
//解决:修改a文件导致b文件的contenhash值变化导致缓存失效的问题
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}`
},
minimizer:{
//配置生产环境的压缩方案: js和css
...
}
}
}