webpack:概念及基本使用

154 阅读3分钟

webpack概念及基本使用

配置示例:

module.exports={
entry:'./src/index.js',//打包入口,零配置webpack默认值
 output:'./dist/main.js',//打包输出,零配置webpack默认值
 mode:'production',//环境
 module:{
   rules:[//loader配置
    {test:/.txt$/,use:'raw-loader'}
  ]
}
 plugins:[//插件配置
new HtmlwebpackPlugin({
template:'./src/index.html'
})
]
}

一、概念

1.入口Entry

单入口:Entry是字符串

多入口:Entry是对象

2.输出Output

打包后文件输出到磁盘的目录

单入口

示例:

module.exports={
entry:'./src/index.js',
 output:{
   filename:'xxx.js',
   path:__dirname+'/dist'
}
}

只需要指定filename和path即可

多入口

示例:

module.exports={
entry:{
app1:'./src/app1/index.js',
app2:'./src/app2/index.js',
},
output:{
  filename:'[name].js',
  path:__dirname+'/dist'
}
}

通过占位符确保名称唯一。

3.支持多种文件类型Loaders

作用

webpack只支持js和json,通过loader支持其他文件格式并转换为有效模块,使之可以添加到依赖图中。

本身是一个函数,接收源文件参数,返回转换结果。

常见loaders

  • babel-loader:转换ES6、ES7等新特性语法
  • css-loader:支持css文件
  • less-loader:将less转换为css
  • ts-loader:将TS转换为JS
  • file-loader:将文件(一般是图片、字体等)打包
  • raw-loader:将文件以字符串形式导入
  • thread-loader:多进程打包js与css

用法

module.exports={
...
 module:{
   rules:[//loader配置
    {test:/.txt$/,use:'raw-loader'}//use可以是字符串也可以是数组
  ]
}
 ...
}

test指定匹配规则;use指定使用的loader,use可以是字符串也可以是数组;

use调用顺序是类似于,因此要把先执行的loader放到后面。比如:css-loader要放在style-loader后,实际上是先解析css为commonjs对象,然后再通过style标签插入head。

4.插件plugin

用于bundle文件的优化,资源管理和环境变量注入。

作用于整个构建过程。

常见plugin

  • CommonsChunkPlugin:将chunks相同的模块代码提取成公共js
  • CleanWebpackPlugin:清理构建目录
  • ExtractTextWebpackPlugin:将css从bundle文件中提取成独立的css文件
  • CopyWebpackPlugin:将文件或者文件夹拷贝至构建的输出目录
  • HtmlWebpackPlugin:创建HTML文件去承载输出的bundle
  • UglifyjsWebpackPlugin:压缩js,Uglify:混淆
  • ZipWebpackPlugin:将打包的资源生成一个zip包

用法:添加至plugin数组即可。

5.环境mode

webpack'4提出,用于指定当前构建环境

选项:production、development、none

可以方便地触发一些内置函数

mode的内置函数功能

选项描述
development设置process.env.NODE_ENV的值为development,开启NamedChunksPluginNamedModulesPlugin
production设置process.env.NODE_ENV的值为production,开启FlagDependencyUsagePluginFlagIncludedChunksPluginModuleConcatenationPluginNoEmitOnErrorsPluginOccurenceOrderPluginSideEffectsFlagPlugin以及TerserPlugin
none不开启任何优化选项

二、使用

1.语法解析

babel

配置文件:.babelrc

preset:可以被看作是一组 Babel 插件和/或 options 配置的可共享模块

plugin:某一项功能的插件,只做一件事

安装

@babel/corebabel-loader

解析ES6+:@babel/preset-env

解析JSX:@babel/preset-reactreactreact-dom

应用

  • 解析ES6+:安装@babel/preset-env,并在.babelrc的preset中添加。
  • 解析JSX:安装@babel/preset-reactreactreact-dom,并在.babelrc的preset中添加@babel/preset-react

2.CSS解析

包括解析CSS、Less、Sass

css-loader用于加载.css文件,并转换为commonjs对象

style-loader将样式通过<style>标签插入到head中

Less和Sass额外使用less-loadersass-loader即可

3.资源文件(字体、图片)解析

使用file-loaderurl-loader都可以解析,url-loader可以设置较小资源自动base64

示例:

{
 test: /.(png|jpg|gif|jpeg|svg)$/,
 use: [
   // 'file-loader',
  {
     loader: "url-loader",
     options: {
     limit:10240//文件小于10*1024则会base64加密
    }
  }
]
},

4.文件监听

在源码更新时自动构建输出,缺点:需要开发者手动刷新浏览器

配置

开启监听模式的方法:

  • 执行webpack命令加上--watch
  • 配置文件webpack.config.js中设置watch=true

配置原理

轮训判断文件的最后编辑时间是否发生改变

某个文件发生了变化,并不会立即告诉监听者,而是先缓存起来,等aggregateTimeout,减少构建次数。

webpack.config.js配置:

module.export={
watch:true,//默认false,不开启
watchOptions:{
//取消监听的目录或文件,默认为空,支持正则
ignored:/node_modules/,
//监听到变化后等待的时间,默认300ms
aggregateTimeout:300,
//判断文件变化是通过不断询问文件是否改变实现的,默认每秒1000次
poll:1000
}
}

5.热更新

HMR:Hot-Module-Replacement

webpack-dev-server

不刷新浏览器

不输出文件,而是放在内存中

一般配合HotModuleReplacementPlugin插件

使用命令webpack-dev-server --open启动,webpack4.x后需要单独安装webpack-cli,并且需要注意webpack和webpack-dev-server的版本兼容

webpack-dev-middleware

将webpack输出的文件输出给服务器,用于灵活的定制场景。

示例:

const express=require('express');
const webpack=require('webpack');
const webpackDevMiddleware=require('webpack-dev-middleware');
​
const app=new express();
const config=require('./webpack.config.js');
const compiler=webpack(config);
​
app.use(webpackDevMiddleware(compiler,{
 publicPath:config.output.publicPath
}));
​
app.listen(3000,function(){
 console.log('create webpack server success!!!\n')
})

原理

image-20220316092920855.png (图片来源:极客时间webpack课件)

  • Webpack Compiler:webpack编译器,最后输出为bundle.js
  • HMR Server:
  • Bundle server:可以使用URL访问
  • HMR Rumtime:注入到浏览器后,bundle.js就能够和服务器建立连接(通常是websocket),用于更新文件

步骤

  1. 启动阶段:编译器通过文件系统把文件给webpack complier打包,把编译好的文件,传输给bundle server,实际上就是启动一个服务器运行工程,允许bundle.js访问。「1,2,A,B」
  2. 更新阶段:fs将更新推送至webpack complier,改动后的代码发送给HMR Server,HMR Server会推送至HMR Runtime,进行浏览器端的自动更新。「1,2,3,4,5」

6.文件指纹

打包输出后的文件名的后缀。

可以确定构建的修改版本,由此可以可以使用未修改的缓存来减少不必要的消耗。

三类文件指纹

  • Hash:整个项目的hash,只要项目代码改动就变化;
  • ChunkHash:与打包的chunk有关,每个entry产生不同的chunkhash;
  • ContentHash:由文件内容定义hash,文件内容改变才改变。

指纹使用

  • JS文件:设置output的filename,使用[chunkHash]
  • CSS文件:配合MiniCssExtractPlugin使用,设置filename,使用[contentHash]
  • 图片等资源文件:设置file-loader对应的options-name,使用[hash]
  • 后面加:表示取的hash的长度
  • chunkhash不能与热更新一起使用。

占位符

占位符含义
[ext]资源后缀名
[name]文件名称
[path]文件相对路径
[folder]所在文件夹
[contenthash]文件内容hash,默认md5生成
[hash]文件内容hash,默认md5生成,同上,不同于外面指纹的项目的hash
[emoji]一个随机指代文件内容的emoj

示例

图片

const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /.(png|svg|jpg|gif)$/,
use: [{
loader: 'file-loader’,
+ options: {
+ name: 'img/[name][hash:8].[ext] '
+ }
}]
}
]
}
};

JS

module.exports = {
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
+ filename: '[name][chunkhash:8].js',
path: __dirname + '/dist'
}
};

CSS

module.exports = {
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name][chunkhash:8].js',
path: __dirname + '/dist'
},
plugins: [
+ new MiniCssExtractPlugin({
+ filename: `[name][contenthash:8].css
+ });
]
};

7.文件压缩

HTML、JS、CSS压缩,减少web服务器传输字节

JS压缩

webpack4.x默认内置uglifyjs-webpack-plugin,代码本身已经被压缩。

若想设置参数,可以单独安装uglifyjsuglifyjs-webpack-plugin然后进行设置。

CSS压缩

Webpack4.x后css-loader不再提供压缩

使用optimize-css-assets-webpack-plugin,同时使用cssnano实现css压缩。

配置

module.exports = {
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name][chunkhash:8].js',
path: __dirname + '/dist'
},
plugins: [
+ new OptimizeCSSAssetsPlugin({
+ assetNameRegExp: /.css$/g,
+ cssProcessor: require('cssnano’)
+ })
]
};

HTML压缩

html-webpack-plugin

使用minify可以进行压缩参数的设置。

一个页面对应一个HtmlWebpackPlugin

inject参数决定了打包出来的文件是否注入html,注意output的publicPath,生产环境要注意去掉。

module.exports = {
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name][chunkhash:8].js',
path: __dirname + '/dist'
},
plugins: [
+ new HtmlWebpackPlugin({
  //html模板所在的位置,使用ejs语法
+ template: path.join(__dirname, 'src/search.html’),
  //指定打包出来的文件的名字
+ filename: 'search.html’,
  //
+ chunks: ['search’],
  //打包出来的文件是否注入html
+ inject: true,
+ minify: {
+ html5: true,
+ collapseWhitespace: true,
+ preserveLineBreaks: false,
+ minifyCSS: true,
+ minifyJS: true,
+ removeComments: false
+ }
+ })
]
};


\