webpack的核心功能
webpack的核心功能是找出模块之间的依赖关系,按照一定的规则把这些模块组织、合并为一个JS文件
预处理器和插件
预处理器是用来解析模块的。插件与预处理器的目的是不一样的
,插件是在webpack编译的某些阶段,通过调用webpack对外暴露的api来扩展webpack功能的。
Loader是webpack中的预处理器
webpack在不进行额外配置时,自身只支持对JS文件JSON文件模块的处理。 当webpack自身无法处理魔种文件模块的时候,我们就可以通过配置特定的预处理器,赋予webpack处理该文件的能力
css-loader
css-loader的作用是解析css文件,包括解析@import
等css自身的语法。它的作用仅包括解析css文件,它会将解析后的css文件以字符串的形式打包到js文件中。
css-loader为何不增加功能,在完成对css和解析后,将结果自动插入HTML文件中? 在线上环境中,我们一般需要把css样式提取到单独的css文件中,如果css-loader把css样式插入了html文件,反而会干扰我们的线上代码。
在对线上环境打包的时候,我们就不需要style-loader了,而是通过插件把样式代码提取到单独的文件。
style-loader
将js里面的样式代码插入HTML文件中。 通过动态生成style标签并将其插入HTML文件的head标签中。
file-loader
file-loader是一个文件资源预处理器,处理文件导入语句并替换成它的访问地址,同时把文件输出到相应位置。其中文件导入语句包括JS的import
和css的url()
语句。
url-loader
url-loader是file-loader的增强版,它除支持file-loader的所有功能外,还增加了Base64编码的能力。 url-loader的特殊功能是可以计算出文件的Base64编码,在文件体积小于指定值(单位为Byte)的时候,可以返回一个Base64编码的data URL来访问地址。
私用base64编码的好处是可以减少一次网络请求,从而提升页面加载速度。
babel-loader
对ES6进行转码,转成ES5
vue-loader
用来处理vue组件
模块化
随着JS在网页应用中的大规模使用,不能模块化限制了它的发展。
这个时候社区中出现了一些模块化规范,比较著名的有CommonJS、AMD和CMD等。通过遵守这些规范,JS就可以进行模块化使用。 社区的模块化规范可以解决大部分JS模块化的问题,但各种模块化规范并不同意,有学习和兼容成本。于是,JS在制定ES6标准的时候,提出了自己的模块化方案,也就是现在的ES6 Module.
目前,JS模块化使用的主要是ES6 Module和CommonJS这两种,后者在Node.js开发领域非常流行。
webpack在打包的时候,碰到import()
函数导入的模块并不会立刻把该模块内容打包到当前文件中。webpack会使用动态生成JS的方式,在运行代码的时候生成script标签,script标签引入的就是import()
导入的内容。import()
函数导入模块后会返回一个Promise对象,我们可以通过import().then()
的方式来处理后续的异步工作。
对于commonJS的模块化,webpack实现了动态导入模块的语法支持。我们可以通过require.ensure
来动态导入模块,注意,该语法是webpack特有的,现在推荐使用import()
函数做动态导入模块。
javascript
// dependencies是一个数组,表示需要动态导入的模块,callback是成功回调,errorCallBack是失败回调,chunkName是自定义的chunk的名称
require.ensure(dependencies,callback,errorCallBack,chunkName)
配置项
entry
webpack资源入口entry需要使用相对路径来表示。entry可以是字符串、数组、对象、函数形式。
1.entry是字符串形式
表示打包的入口文件
2.entry是数组形式
数组的最后一个文件是资源的入口文件,数组的其余文件会被预先构建到入口文件中。 数组形式的entry本质上还是单一入口。
3.entry是对象形式
对象形式的entry又称为多入口配置。多入口配置就是打包后生成多个JS文件。
javascript
var path = require('path');// path模块是node.js里面的路径解析模块
//__dirname是node.js中的一个全局变量,表示当前文件的路径
// module.exports是commonjs模块导出语法
module.exports = {
// entry: './js/a.js',// webpack资源入口entry需要使用相对路径来表示。entry可以是字符、数组、对象、函数和描述符形式
entry: {
app: './js/a.js',
vendor:'./js/b.js',
},
context:path.resolve(__dirname, './src'), // 表示资源入口entry是以哪个目录为起点的。context的值是一个字符串,表示一个绝对路径
output: {
path: path.resolve(__dirname, 'dist'), // path.resolve的作用是将其接受的参数解析成一个绝对路径后返回
// filename: 'bundle.js',
filename:'[name].js'
},
mode: 'none', // node会保留原始的打包结果,还可以是production 和 development
// 对某种模块进行处理,需要为其配置项新增module项。该项是一个对象,其rules里是我们对各个类型文件的处理规则配置
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'], // 预处理器的执行顺序是从后向前执行,先执行css-loader,然后把css-loader的执行结果交给style-loader执行
},
],
},
};
上面的配置会打包出app.js
和vendor.js
两个文件
4.entry是函数形式
函数形式的entry,webpack取函数返回值作为入口配置,返回值是上述三种形式之一即可。 函数形式的entry可以用来做一些额外的逻辑处理,不过在自己搭脚手架时很少使用。
context是一个绝对路径,是基础目录的意思。entry是一个相对路径,它与context拼接起来,就是webpack打包的入口文件了。
output
output配置项表示打包后输出的目录。output的值是一个对象,它有几个重要的属性filename、path、publicPath、chunkFilename。
filename是打包后生成的资源名称。filename支持类似变量的方式生成动态文件名,如[name]-[fullhash]-bundle.js
,输出的文件名如vendor-7cc137a8f6f2af43b4d6-bundle.js
。
path表示资源打包后输入的位置,该位置地址需要的是绝对路径。如果不设置它,webpack默认其为dist目录。 需要注意的是,path表示的是在磁盘上构建生成的真实文件的存放地址。我们在开发时,一般会用webpack-dev-server
来启动一个本地服务器,该服务器可以自动刷新和热加载等,它生成的文件存放在内存中而不是在电脑磁盘中。对于该内存中的文件路径,我们会用webpack配置文件的devServer配置项的publicPath表示。
publicPath表示的是资源访问路径,在web开发时其默认值是字符串auto,表示资源的输出位置和访问位置在同一目录下。资源输出位置表示的是本次打包完成后,资源存放在磁盘中的位置。资源访问位置用publicPath来表示,提供给浏览器访问。
chunkFilename表示的是打包过程中非入口文件的chunk名称,通常在使用异步模块的时候,会生成非入口文件的chunk.
Babel
Babel是一系列工具,在使用webpack打包时,主要使用babel-loader这个预处理器。webpack主要调用该处理器来使用Babel的功能,将ES6代码转成ES5代码。
使用babel-loader的时候需要先安装相应的npm包。
java
//安装Babel核心包及其babel-loader
npm install @babel/core babel-loader
选择使用@babel/preset-env这个预设进行转码,所以也需要安装他
bash
npm install -D @babel/preset-env
对于babel配置较复杂的情况,可以在工程根目录下单独建立一Babel配置文件,如babel.config.js
。将presets和plugins等配置项写在babel.config.js文件中,babel-loader会自动读取文件并使用该默认配置文件的配置。
插件
插件是webpack的骨干,webpack自身也建立于插件系统之上。
像一些本地资源,如图片和音视频,在打包过程中没有任何模块使用他们,但是我们想要把他们存放到打包后的资源输出目录下。预处理器就不适合做这样的事情,这个时候就需要使用插件,copy-webpack-plugin
可以帮助完成文件复制。terser-webpack-plugin
压缩JS资源,css-minimizer-webpack-plugin
压缩css资源。
将样式代码提取到单独的css文件中会用到mini-css-extract-plugin
插件。
javascript
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 用于提取css文件
module.exports = {
entry: './js/a.js', // webpack资源入口entry需要使用相对路径来表示。entry可以是字符、数组、对象、函数和描述符形式
context: path.resolve(__dirname, './src'), // 表示资源入口entry是以哪个目录为起点的。context的值是一个字符串,表示一个绝对路径
output: {
path: path.resolve(__dirname, 'dist'), // path.resolve的作用是将其接受的参数解析成一个绝对路径后返回
filename: 'bundle.js',
assetModuleFilename: 'static/[hash:8][ext][query]', // 这里也可以配置生成的文件名
},
mode: 'none', // node会保留原始的打包结果,还可以是production 和 development
// 对某种模块进行处理,需要为其配置项新增module项。该项是一个对象,其rules里是我们对各个类型文件的处理规则配置
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
],
include: /src/,
exclude: /node_modules/, // exclude的优先级大于include
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name]-[contenthash:8].css', // 同步代码里提取的文件名
chunkFilename: '[id].css',// 异步代码提取的css文件名
}),
], // plugins数组的每一个元素都是插件构造函数创建出来的一个实例
};
webpack-dev-server
webpack-dev-server
是webpack官方提供的一个webpack服务工具,一般也称为devServer。它会在本地开启一个网络服务器,可以用来处理网络请求。
webpack-dev-server
是一个npm包,安装指令如下
vbscript
npm install -D webpack-dev-server
启动方式
npx webpack serve
npx node的命令行工具,它允许你直接从命令行运行项目中的包,而无须知道包的具体路径。
模块热更新
webpack提供了模块热更新的功能,其英文名是"Hot Module Replacement",简称HMR。不需要重新刷新页面,而只是通过重新加载修改过的模块来实现实时预览。
在使用模块热替换的功能是,需要使用webpack.HotModuleReplacementPlugin插件的能力。在webpack5中,将该参数设置为true,会自动添加该插件,不需要进行额外的配置。
sourceMap
source map是一个单独的文件,浏览器可以通过它还原出编译前的原始代码。
开启方式,在webpack.config.js中配置devtool属性
vbnet
devtool:'source-map'
source map最初会生成一个单独的后缀名是.map的文件。 官方文档中devtool的取值有二十多种,重点要理解下面6个词的含义
- cheap: 一种速度较快的选择,这样生成的source map 中没有列信息而只有行信息,编译计算量少,不过在这种情况下,预处理器输出的source map信息不回被采用。
- module:预处理器输出的source map 信息会被采用,这样可以看到预处理器处理前的原始代码。
- inline:将生成的source map 内联到bundle中,该source map 默认是base64编码的data url 4)eval:使用eval包裹模块代码,可以提供rebuild的速度。
- hidden: bundle里不包含source map 的引用地址,这样在浏览器开发者工具里看不到原始的代码
- nosource: bundle不包含原始代码
开发环境
建议对devtool取值eval-cheap-module-source-map
,该配置能保留预处理器处理前的原始代码信息,并且打包速度也不满,是一个较佳的选择。
生产环境
在生产环境中,一般不生成source map,如果一定需要的话,可以选择hidden-source-map或者白名单策略。
Asset Modules
Asset Modules通常被翻译为资源模块,它指的是图片和字体等这一类型文件模块,它们无须使用额外的预处理器,webpack通过一些配置就可以完成对他们的解析。该功能是webpack5新加入的,与file-loader等预处理器的功能很像。
Asset Modules的几个主要配置项都存放在module.rules,关键的配置项叫type,它的值有以下四种
- asset/resource: 与file-loader功能很像,处理文件导入地址并将其替换成访问地址,同时把文件输出到相应位置。
- asset/inline: 与url-loader很像,处理文件导入地址并将其替换为data url,默认是Base64格式编码的url。
- asset/source: 与raw-loader很像,以字符串形式导出文件资源。
- asset: 在导出单独的文件和data url 间自动选择,可以通过修改配置项影响自动选择的标准。
工具和环境变量
webpack-merge工具
webpack-merge
这个工具,它类似于Object.assign方法,但它比Object.assign更加强大,非常适合对webpack配置项进行合并。 业内流行的配置方案是把开发和生产环境公共的配置提取到一个单独的文件里(webpack.common.js),然后分别维护一份开发环境的配置文件(webpack.development.js),一份生产环境的配置文件(webpack.production.js),并将公共配置文件的JS代码合并到这两个文件里。
php
// webpack.production.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = merge(common, {
mode: 'development',
module: {
rules: [
{
test: '/.css$/',
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
plugins: [new MiniCssExtractPlugin({
filename: '[name]-[contenthash:8].css',
chunkFilename: '[id].css'
})],
});
环境变量
在使用webpack的过程中,会遇到以下两种环境变量
- Node.js环境里的环境变量
- Webpack打包模块里的环境变量
Node.js里的环境变量
Node.js环境里的变量,存放在process.env模块中 在实际开发环境中,一般需要设置跨操作系统的环境变量。通常,在npm的package.json文件中,我们可以通过跨操作系统的cross-env MY_ENV=dev
这种方式进行环境变量的设置。cross-env
是一个npm包,安装完成后就可以使用它了。
sql
npm install -D cross-env
在package.json文件中增加如下的脚本命令
json
"scripts": {
"build": "cross-env MY_ENV=dev webpack",
},
Webpack打包模块里的环境变量
Webpack打包模块里的环境变量指webpack所打包文件里的环境变量,通过DefinePlugin
插件来设置打包模块里的环境变量,它是webpack自带的插件。
php
const webpack = require('webpack');
//...
plugins: [
new webpack.DefinePlugin({
IS_OLD: true,
MY_ENV: JSON.stringify('dev'),
NAME:'ROSE',
})
],
可以在打包出的bundle.js文件中访问到这些变量。
性能提示
在webpack配置文件里,可以用performance配置项进行性能提示。
javascript
performance: {
hints:'error',// 可配置warning、error、false,默认值是warning
maxEntrypointSize: 3 * 1024,// 入口资源(打包出的css文件、js文件)的最大体积,超过该值就会提示
maxAssetSize: 36 * 1024,//打包资源的最大体积,超过该值就会进行信息提示
assetFilter: function(assetFilename) { return !/\.map$/.test(assetFilename); } // 过滤掉.map文件,一般不需要改动
}
性能优化
资源体积大小分析插件webpack-bundle-analyzer
打包过程中预处理器和插件等花费的时间speed-measure-webpack-plugin
资源压缩:一般用terser-webpack-plugin
进行JS文件压缩,webpack5会默认安装这个插件,所以不需要单独安装。 有些模块不需要被解析处理,如jquery和lodash,可以告知webpack保留原始模样
css
module: {
noParse:/jquery|lodash/,
},