webpack功能
打包:将不同类型资源按模块处理进行打包
静态:打包最后产出静态资源
模块:webpack支持不同规范的模块化开发

1、Loader

起到转换的作用,把当前代码转成webpack能识别处理的模块
webpack5中,在cli里面写loader的方式已经被废弃

CSS-Loader和style-loader

npm i css-loader style-loader -D
行内loader,单独使用不会报错,但是不会起作用,还要加上style-loader

  1. import 'css-loader!../css/login.css'
  2. function login() {
  3. const oH2 = document.createElement('h2')
  4. oH2.innerHTML = '拉勾教育前端'
  5. oH2.className = 'title'
  6. return oH2
  7. }
  8. document.body.appendChild(login())

配置文件

  1. const path = require('path')
  2. module.exports = {
  3. ...
  4. module: {
  5. rules: [
  6. {
  7. test: /\.css$/,
  8. use: ['style-loader', 'css-loader']
  9. }
  10. ]
  11. }
  12. }

如果有less或者sass,则新增一个less-loader处理

  1. {
  2. test: /\.less$/,
  3. use: ['style-loader', 'css-loader', 'less-loader']
  4. }

browserslistrc和postcss

  1. > 1%
  2. last 2 version
  3. not dead

使用postcss处理CSS兼容之前需要进行配置
www.caniuse.com 浏览器兼容性查询网站,node_modules里browserslist包会去这个网站匹配
>1%,兼容处理市面上占有率大于1%的浏览器
deafault,0.5%
dead 24个月没更新,没支持
last 2 version 最新的2个版本
也可以直接在package.json里配置browserslist属性

postcss

利用js来转换样式做兼容的工具,在不兼容的css属性和值前面加上前缀
如果是使用postcss-cli命令行手动的话,就是根据之前写的browserslistrc配置信息,然后使用autoprefixer来进行css修改
npm i postcss-cli autoprefixer -D
npx postcss --use autoprefixer -o rest.css ./src/css/test.css

webpack里则可以通过loader
npm i postcss-loader -D

  1. {
  2. test: /\.css$/,
  3. use: [
  4. 'style-loader',
  5. 'css-loader',
  6. 'postcss-loader'
  7. ]
  8. }

npm i postcss-preset-env -D
color的rgba写法或者一些新特性,部分浏览器无法兼容,使用postcss-preset-env这个预设的插件集合来进行处理,这个集合里已经有之前使用的autoprefixer

  1. {
  2. test: /\.css$/,
  3. use: [
  4. 'style-loader',
  5. 'css-loader',
  6. {
  7. loader: 'postcss-loader',
  8. options: {
  9. postcssOptions: {
  10. plugins: ['postcss-preset-env']
  11. }
  12. }
  13. }
  14. ]
  15. }

复用配置属性

但是,此时如果有less或者sass的时候,又需要把前面写的重新写一份,这样代码就冗余,webpack提供了一种复用的额外配置方式
在项目根目录下创建postcss.config.js

  1. module.exports = {
  2. plugins: [
  3. // require('postcss-preset-env')
  4. require('autoprefixer')
  5. ]
  6. }

之后,就可以直接写postcss,不用多写插件配置

  1. {
  2. test: /\.css$/,
  3. use: [
  4. 'style-loader',
  5. 'css-loader',
  6. 'postcss-loader'
  7. ]
  8. },
  9. {
  10. test: /\.less$/,
  11. use: [
  12. 'style-loader',
  13. 'css-loader',
  14. 'postcss-loader',
  15. 'less-loader'
  16. ]
  17. }

导入样式处理

之前我们处理的样式兼容,如果是通过@import进来的postcss无法处理

  1. @import './test.css';
  2. .title {
  3. color: #12345678;
  4. }

导入之后,当前css文件交给postcss处理,基于当前的筛选条件,postcss-loader发现不需要处理,交给了css-loader,而css-loader可以处理@import、@media和url等
这个时候它获取到了test.css,但是无法返回给postcss进行处理,只能进行下一步
webpack考虑到了这个情况,提供了importLoaders属性,值为数字,代表遇到了这种情况,往前找第几个loader

  1. {
  2. test: /\.css$/,
  3. use: [
  4. 'style-loader',
  5. {
  6. loader: 'css-loader',
  7. options: {
  8. importLoaders: 1
  9. }
  10. },
  11. 'postcss-loader'
  12. ]
  13. }

图片处理

file-loader

打包图片文件,返回webpack能识别的格式
把要处理的图片资源,用hash改名后拷贝到指定目录,默认是dist目录,然后在使用的地方返回路径
npm i file-loader -D

img src

  1. {
  2. test: /\.(png|svg|gif|jpe?g)$/,
  3. use: ['file-loader']
  4. }
  1. function packImg() {
  2. const oEle = document.createElement('div')
  3. const oImg = document.createElement('img')
  4. oImg.width = 600
  5. oImg.src = require('../img/01.wb.png').default
  6. oEle.appendChild(oImg)
  7. return oEle
  8. }
  9. document.body.appendChild(packImg())

webpack5中,file-loader返回的资源变成了一个对象,其中default属性才是真正需要的资源,要改写法
如果不想这样写,webpack需要改一下配置,esModule,含义是,是否将导出的内容转为esmodule

  1. {
  2. test: /\.(png|svg|gif|jpe?g)$/,
  3. use: [
  4. {
  5. loader: 'file-loader',
  6. options: {
  7. esModule: false // 不转为 esModule
  8. }
  9. }
  10. ]
  11. }
  1. function packImg() {
  2. const oEle = document.createElement('div')
  3. const oImg = document.createElement('img')
  4. oImg.width = 600
  5. oImg.src = require('../img/01.wb.png')
  6. oEle.appendChild(oImg)
  7. return oEle
  8. }
  9. document.body.appendChild(packImg())

还有一种写法,采用esmodule的导入方法,webpack配置改回之前的写法

  1. import oImgSrc from '../img/01.wb.png'
  2. function packImg() {
  3. const oEle = document.createElement('div')
  4. const oImg = document.createElement('img')
  5. oImg.width = 600
  6. oImg.src = oImgSrc
  7. oEle.appendChild(oImg)
  8. return oEle
  9. }
  10. document.body.appendChild(packImg())
  1. {
  2. test: /\.(png|svg|gif|jpe?g)$/,
  3. use: ['file-loader']
  4. }

background src

  1. .bgBox {
  2. width: 240px;
  3. height: 310px;
  4. border: 1px solid #000;
  5. background-image: url('../img/02.react.png');
  6. }
  1. import '../css/img.css'
  2. function packImg() {
  3. const oEle = document.createElement('div')
  4. const oBgImg = document.createElement('div')
  5. oBgImg.className = 'bgBox'
  6. oEle.appendChild(oBgImg)
  7. return oEle
  8. }
  9. document.body.appendChild(packImg())

css文件中使用了url的时候,css-loader在解析时会默认转为对象,所以需要修改配置

  1. {
  2. test: /\.css$/,
  3. use: [
  4. 'style-loader',
  5. {
  6. loader: 'css-loader',
  7. options: {
  8. importLoaders: 1,
  9. esModule: false
  10. }
  11. },
  12. 'postcss-loader'
  13. ]
  14. },
  15. {
  16. test: /\.(png|svg|gif|jpe?g)$/,
  17. use: ['file-loader']
  18. }

配置图片名字和输出的路径

扩展名

  • [ext]: 扩展名
  • [name]: 文件名
  • [hash]: 根据文件内容和MD4算法生成的128位hash值
  • [contentHash]:file-loader里和hash一样
  • [hash:]:固定长度的hash
  • [path]:不常用

输出的路径:dist目录下的文件夹名字,可以写在outputPath属性,也可以直接在名字前面加路径

  1. {
  2. test: /\.(png|svg|gif|jpe?g)$/,
  3. use: [
  4. {
  5. loader: 'file-loader',
  6. options: {
  7. name: 'img/[name].[hash:6].[ext]'
  8. //outputPath: 'img'
  9. }
  10. }
  11. ]
  12. }

url-loader

npm i url-loader -D
把要打包的图片资源以base64 URI的方式加载到代码里
优点:只需要请求一次,减少请求次数
缺点:当前图片如果过大,一次性请求的数据量过大,请求速度可能达不到业务要求
所以,需要限制使用url-loader时的图片大小,使用limit属性进行限制,超过限制的url-loader会自动去调用已经安装的file-loader

  1. {
  2. test: /\.(png|svg|gif|jpe?g)$/,
  3. use: [
  4. {
  5. loader: 'url-loader',
  6. options: {
  7. name: 'img/[name].[hash:6].[ext]',
  8. limit: 25 * 1024
  9. }
  10. }
  11. ]
  12. }

asset

webpack5中新增的处理图片和字体的资源类型模块,不需要再使用loader

图片

asset module type可以直接写type的值为下面3个,代表之前的loader

  • asset/resource —>file-loader( 输出路径 )
  • asset/inline —->url-loader(所有 data uri)
  • asset/source —->raw-loader
  • asset (parser )
    1. output: {
    2. filename: 'main.js',
    3. path: path.resolve(__dirname, 'dist'),
    4. assetModuleFilename: "img/[name].[hash:4][ext]"
    5. }
    6. ....
    7. {
    8. test: /\.(png|svg|gif|jpe?g)$/,
    9. type: 'asset/resource',
    10. }
    上面这样的话,名称修改就变成全局的了,不太合适,所以要改到图片处理部分写generator
    1. {
    2. test: /\.(png|svg|gif|jpe?g)$/,
    3. type: 'asset',
    4. generator: {
    5. filename: "img/[name].[hash:4][ext]"
    6. },
    7. parser: {
    8. dataUrlCondition: {
    9. maxSize: 30 * 1024
    10. }
    11. }
    12. }

    字体

    1. {
    2. test: /\.(ttf|woff2?)$/,
    3. type: 'asset/resource',
    4. generator: {
    5. filename: 'font/[name].[hash:3][ext]'
    6. }
    7. }

    2、plugin插件

    loader对特定的文件类型进行转换,在读取某一个特定类型的资源时开始工作
    plugin可以做更多事情,在打包的生命周期中任一钩子来操作

    clean-webpack-plugin

    和之前的一样用,npm i clean-webpack-plugin -D安装,然后导入使用
    1. const {CleanWebpackPlugin} = require('clean-webpack-plugin')
    2. plugins:[new CleanWebpackPlugin()]

    html-webpack-plugin

    npm i html-webpack-plugin -D
    在dist目录下创建html,并且自动引入JS文件,DefinePlugin是webpack内置,用来使用公共变量的插件 ```javascript const { DefinePlugin } = require(‘webpack’) const { CleanWebpackPlugin } = require(‘clean-webpack-plugin’) const HtmlWebpackPlugin = require(‘html-webpack-plugin’)

plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ title: ‘html-webpack-plugin’, template: ‘./public/index.html’ }), new DefinePlugin({ BASE_URL: ‘“./“‘ }) ]

  1. index.html的模板
  2. ```javascript
  3. <!DOCTYPE html>
  4. <html lang="">
  5. <head>
  6. <meta charset="utf-8">
  7. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  8. <meta name="viewport" content="width=device-width,initial-scale=1.0">
  9. <link rel="icon" href="<%= BASE_URL %>favicon.ico">
  10. <title>
  11. <%= htmlWebpackPlugin.options.title %>
  12. </title>
  13. </head>
  14. <body>
  15. <noscript>
  16. <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
  17. Please enable it to continue.</strong>
  18. </noscript>
  19. <div id="app"></div>
  20. <!-- built files will be auto injected -->
  21. </body>
  22. </html>

copy-webpack-plugin

npm i copy-webpack-plugin -D
将静态资源拷贝到dist目录下

const CopyWebpackPlugin = require('copy-webpack-plugin')
const { DefinePlugin } = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

plugins: [
  new CleanWebpackPlugin(),
  new HtmlWebpackPlugin({
    title: 'copyWebpackPlugin',
    template: './public/index.html'
  }),
  new DefinePlugin({
    BASE_URL: '"./"'
  }),
  new CopyWebpackPlugin({
    patterns: [
      {
        from: 'public',
        globOptions: {
          ignore: ['**/index.html']
        }
      }
    ]
  })
]

babel

babel是一个JS编译器,用来转换最新的JS语法,把ES6, ES7等语法转化成ES5语法,从而能够在大部分浏览器中运行
编译过程:
1.parse分析:第一步是babel使用babylon将原始代码转换为AST抽象语法树
2.transform转化:第二步是babel通过babel-traverse对前面的抽象语法树进行遍历修改并获得新的抽象语法树
3.generator生成代码:第三步是babel使用babel-generator将抽象语法树转换为代码
这三个操作通过babel-core合成一个对外的api供外界使用

babel-loader
npm i babel-loader @babel/core @babel/preset-env -D

{
  test: /\.js$/,
  use: ['babel-loader']
}

根目录下创建babel.config.js

module.exports = {
  presets: ['@babel/preset-env']
}

也可以直接写

{
  test: /\.js$/,
  use: [
    {
      loader: 'babel-loader',
      options: {
        presets: ['@babel/preset-env']
      }
    }
  ]
}

polyfill

babel默认只转化新的js句法,而不会处理新的API,所以需要polyfill来处理,它会新增对应的方法
webpack5之后要优化速度,polyfill包太大,不需要安装@babel/polyfill,自己配置
npm i core-js regenerator-runtime
注意的是,我们用的第三方包可能也用到了一些新的API,但是我们的代码没有,如果是usage不会填充进来,所以还是使用entry

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        // false: 不对当前的JS处理做 polyfill 的填充
        // usage: 依据用户源代码当中所使用到的新语法进行填充
        // entry: 依据我们当前筛选出来的浏览器决定填充什么
        useBuiltIns: 'entry',
        corejs: 3
      }
    ]
  ]
}