3

带你上手全新版本的 Webpack 5

 2 years ago
source link: https://www.techug.com/post/take-you-to-the-new-version-of-webpack-5.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

​​摘要:webpack5 快速入门,船新版本,建议收藏

本文分享自华为云社区《webpack5快速入门,船新版本,建议收藏》,作者:北极光之夜。。

一. 快速上手

1.1 Webpack 功能:

打包: 将不同类型资源按模块处理进行打包。

静态: 打包后最终产出静态资源。

模块: webpack 支持不同规范的模块化开发

1.2 安装 webpack:

终端输入: npm install webpack -g

1.3 快速模拟搭建一个项目目录:

utiles.js:

function add(a,b){
    console.log(a+b);
}
export {add} ;

index.js:

import {add} from './utiles/utiles.js'
add(6,9);

1.4 webpack 打包:

终端输入:webpackwebpack 会自动寻找 src 目录,然后寻找 index.js 入口文件,然后进行打包,最终生成一个 dist 目录为打包后内容。

index.html 引入:

<script src="../dist/main.js"></script>

二.基本使用:

2.1.配置文件:

可以在配置文件里定义配置,表示你想如何打包,能设置很多条件。webpack 会根据你配置文件的配置规则来进行打包。在 src 同级目录下新建一个 webpack.config.js 文件,里面写配置信息。如最基本的入口和出口:

const path = require('path');
module.exports = {
  //打包入口文件路径
  entry: './src/index.js',
  //path打包出口路径,filename写打包后文件名
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'build.js',
  },
};

终端输入 webpack 后成功打包了 build.js 文件,跟上面打包的 main.js 内容一样:

2.2.loader:

为什么使用 loader:webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 能让 webpack 能够去处理其他类型的文件(比如 css 类型文件,图片类型,txt 类型等等),并将它们转换为有效模块,以供使用。

2.2.1 css-loader:

比如,我想 webpack 能打包 css,终端输入以下命令先安装 css-loader:

npm i css-loader -D

1.可以在导入 css 文件的时候指定 loader,这样就不报错了,在导入 css 文件路径前添加 css-loader!:

import 'css-loader!./css/index.css'

2.当然,也可以在配置文件设置:

const path = require('path');
module.exports = {
  //打包入口文件路径
  entry: './src/index.js',
  //path打包出口路径,filename打包后文件名
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'build.js',
  },
  //定义一些规则
  module: {
      //数组里每个元素为一个规则
     rules:[
        {
            test: /\.css$/,
            use: [
                {loader: 'css-loader'}
            ]
          //简写为 use: ['css-loader']    
        }
     ]
  }
};

test 属性,定义一个正则表达式,匹配需要处理的文件类型。识别出哪些文件会被转换。use 属性,定义出在进行转换时,应该使用哪个 loader。配置文件里配置后,别忘了在 index 入口文件导入 css 文件。

2.2.2 style-loader:

上面 css-loader 只是能识别 css 文件,而引入了 style-loader 后 css 样式才能在页面展示。

npm i style-loader -D

配置文件规则:

因为 webpack 是 从 后 往 前 执 行 ,所以 style-loader 写在 css-loader 前面。

module: {
      //数组里每个元素为一个规则
     rules:[
        {
            test: /\.css$/,
            use: ['style-loader','css-loader']
        }
     ]
  }

2.2.3 sass-loader:

比如,我想 webpack 能打包 scss 文件类型。不会 sass 的可以看这篇文章文章 sass 全解析。

安装 sass:

npm i sass -D

转换 scss 为 css(注意在 scss 同级路径下转换,也是终端输入):

sass index.scss:ouput.css

在入口文件 index.js 导入:

import './css/ouput.css'

安装 sass-loader:

npm i sass-loader -D

配置规则:

 //定义一些规则
  module: {
      //数组里每个元素为一个规则
     rules:[
        {
            test: /\.css$/,
            use: ['style-loader','css-loader']
        },
         {
            test: /\.scss$/,
            use: ['style-loader','css-loader']
        }
     ]
  }
webpack

2.3 browserslist:

Webpack 支持所有符合 ES5 标准 的浏览器(不支持 IE8 及以下版本)。如果你想要支持旧版本浏览器,那就需要借助到一些工具了。在安装 webpack 时默认安装了 browserslist,它可以知道各个浏览器的占有率数据并配置。

这个网站也可以查到目前各个浏览器的占有率数据。后面再详细讲。

2.4 postcss-loader 处理 css 兼容:

postcss 是 JavaScript 转换样式的工具,这个工具能处理 css 兼容问题。就是这个工具能给我们写的 css 代码添加一些兼容的前缀。

首先,你可以通过 这个网站 了解 css 是添加什么前缀怎么能兼容主流浏览器的。

npm i postcss-loader -D
npm i autoprefixer -D

配置文件:

在 css 文件类型里添加 postcss-loader,并配置参数 :

{
            test: /\.css$/,
            use: [
                'style-loader',
                'css-loader',
                //添加postcss-loader
                {
                    loader:'postcss-loader',
                    //配置参数
                    options:{
                       postcssOptions:{
                           //添加插件autoprefixer,能加前缀
                           plugins:[
                               require('autoprefixer')
                           ]
                       }
                    }
                }
            ]
        },

在 index.js 同级下新建一个名为.browserslistrc 文件,里面写兼容的条件,如:

> 0.1%
last 2 version
not dead

然后终端输入 webpack 打包后 css 代码会自动添加兼容代码。

上面只是添加前缀,如果还需要更强的兼容需要 postcss-preset-env,安装:

npm i  postcss-preset-env -D

添加配置(来次全的):

const path = require('path');
module.exports = {
  //打包入口文件路径
  entry: './src/index.js',
  //path打包出口路径,filename打包后文件名
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'build.js',
  },
  //定义一些规则
  module: {
      //数组里每个元素为一个规则
     rules:[
        {
            test: /\.css$/,
            use: [
                'style-loader',
                'css-loader',
                //添加postcss-loader
                {
                    loader:'postcss-loader',
                    //配置参数
                    options:{
                       postcssOptions:{
                           //添加插件autoprefixer,能加前缀
                           plugins:[
                               require('autoprefixer'),
                               require('postcss-preset-env')
                           ]
                       }
                    }
                }
            ]
        },
         {
            test: /\.scss$/,
            use: ['style-loader','css-loader']
        }
     ]
  }
};

可以只保留 postcss-preset-env,简写:

 {
            test: /\.css$/,
            use: [
                'style-loader',
                'css-loader',
                //添加postcss-loader
                {
                    loader:'postcss-loader',
                    //配置参数
                    options:{
                       postcssOptions:{
                           //添加插件autoprefixer,能加前缀
                           plugins:['postcss-preset-env']
                       }
                    }
                }
            ]
        },

不过一般是在 index.js 同级下新建一个 postcss.config.js 文件专门写配置:postcss.config.js 文件内容:

module.exports = {
    plugins: [
        require('postcss-preset-env')
    ]
}

然后在 webpack.config.js 配置文件里直接导入 postcss-loader 就行:

use: [
                'style-loader',
                'css-loader',
                //添加postcss-loader
                 'postcss-loader'
            ]

2.5 importLoaders:

importLoaders:用于配置「css-loader 作用于 @import 的资源之前」有多少个 loader。直白来说就是 importLoaders 设置几,那么通过 @import 导入的 css 文件也会向前执行前面不再执行的 loader。如下:

 use: [
                'style-loader',
                {
                   loader:'css-loader',
                   options:{
                       importLoaders:1
                   }
                },
                 'postcss-loader'
            ]

本来一个 css 文件会执行上面 3 个 loader,如果那个 css 文件存在通过 import 语法导入的 css 文件,那么那个导入的 css 文件是不会执行最后的 postcss-loader。但是我想执行,所以配置 importLoaders,表示 import 导入的 css 文件也会向后执行多少个 loader。(注意 webpack 是从后往前执行的)

2.6 file-loader 处理图片:

file-loader 作用:

1.当我们把图片当一个模块导入的时候可以识别它。2.可以把二进制资源拷贝一份到指定目录,没指定就是默认 dist 目录。

npm i file-loader -D 

2.6.1 在 js 里通过 src 导入的:

可以在 src 目录下新建一个 img 文件夹存放图片。

配置文件(在 rules 数组里继续新增一个规则):

{
            test: /\.(png|svg|gif|jpe?g)$/,
            use:['file-loader']
        }

1. 第一种用法:当把图片当成一个模块导入时在末尾添加.default,比如:

 var img = document.createElement('img');
    img.src = require('../img/1.jpg').default;
    document.body.appendChild(img);

2. 第二种用法:如果不想模块导入时在末尾添加.default,那么在配置文件里添加参数 esModule:

{
            test: /\.(png|svg|gif|jpe?g)$/,
            use:{
                loader:'file-loader',
                options: {
                    esModule:false
                }
            }
        }

3. 第三种用法:如果你也不想上面这样写,还可以通过 es6 模块导入方式:

先导入图片模块:

import src from '../img/1.jpg';
var img = document.createElement('img');
   img.src = src;
   document.body.appendChild(img);

最后终端 webpack 打包就行,目前会将图片默认打包到 dist 目录。

2.6.2 在 css 里通过 url 导入的:

跟上面 src 区别就是要修改的是 css 类型文件规则,加一个 esModule 参数:

{
            test: /\.css$/,
            use: [
                'style-loader',
                {
                   loader:'css-loader',
                   options:{
                       importLoaders:1,
                       esModule:false
                   }
                },
                 'postcss-loader'
            ]
        },
          {
            test: /\.(png|svg|gif|jpe?g)$/,
            use: ['file-loader']
        }

然后在 css 里通过 url 正常引用即可,webpack 打包后会将图片默认打包到 dist 目录:

div {
  width: 200px;
  height: 200px;
  background-image: url("../img/1.jpg");
}

默认位置,如(图片名称自动根据内容算法得出):

2.6.3 设置输出位置与图片名称:

我们可以设置打包后的图片存放到的地方与名称。

修改配置文件的图片规则,添加一个 name 配置(名称)属性和 outputpath 属性(位置):

 {
            test: /\.(png|svg|gif|jpe?g)$/,
            use: {
                loader:'file-loader',
                options:{
                    name: '[name].[hash:6].[ext]',
                    outputPath: 'img'
                }
            }
        }

其中 name 属性里表示:【ext】扩展名,【name】文件名,【hash】文件内容。outputpath 属性:直接指定 img 目录,默认会放在 dist 目录下。

两个属性可以合并直接简写为:

 {
            test: /\.(png|svg|gif|jpe?g)$/,
            use: {
                loader:'file-loader',
                options:{
                    name: 'img/[name].[hash:6].[ext]',
                }
            }
        }

2.7 url-loader 处理图片:

url-loader 可以将图片转为 base64 字符串,能更快的加载图片(适用图片文件较少情况,过大的话还是用 file-loader)。file-loader 相对于拷贝,速度较慢。

npm i url-loader -D

配置其实跟 file-loader 差不多的,把 loader 那一改就行:

{
            test: /\.(png|svg|gif|jpe?g)$/,
            use: {
                loader:'url-loader',
                options:{
                    name: 'img/[name].[hash:6].[ext]',
                }
            }
        }

与 file-loader 不同的是,打包后图片会以 base64 字符串形式加载到代码里,所以目录里不再可见:

关键的是,其实 url-loader 包含 file-loader ,可以设置一个 limit 属性,当图片大小超过 limit,url-loader 会自认不行,会主动去调用 file-loader 去执行。

如下:设置一个筏值 20kb,小于它会执行 url-loader,大于它会执行 file-loader

{
            test: /\.(png|svg|gif|jpe?g)$/,
            use: {
                loader:'url-loader',
                options:{
                    name: 'img/[name].[hash:6].[ext]',
                    limit: 20*1024
                }
            }
        }

2.8 asset 处理图片:

webpack5 之后可以直接使用 asset 处理图片,不必再配置 file-loader 或 url-loader。能更好的简化使用。且它是 webpack5 内置模块,不必额外进行安装其它东西。

配置文件修改图片规则:

1. 默认情况,拷贝图片,默认放到 dist 目录下(跟 file-loader 没配置名称和路径时结果一样):

{
            test: /\.(png|svg|gif|jpe?g)$/,
            type: 'asset/resource'
        }

2. 指定图片打包后位置,放到 dist 下的 img 文件夹里,图片规则跟上面一样,要修改的是 output 打包出口路径那里,新增 assetModuleFilename:

//path打包出口路径,filename打包后文件名
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'build.js',
    assetModuleFilename:'img/[name].[hash:6][ext]'
  },
    {
            test: /\.(png|svg|gif|jpe?g)$/,
            type: 'asset/resource'
        }

3. 上面相当于全局配置,不论什么图片都会执行,所以不大好,所以还是在规则里面加图片输出位置与名称好点,新增 generator,里面的 filename 写位置与名称:

 {
            test: /\.(png|svg|gif|jpe?g)$/,
            type: 'asset/resource',
            generator:{
                filename:'img/[name].[hash:6][ext]'
            }
        }

4. 如果想将图片转为 base64 字符串,而不是拷贝的话,修改规则如下:

{
        test: /\.(png|svg|gif|jpe?g)$/,
        type: 'asset/inline',
    }  

5. 当然,也能像 url-loader 设置 limit 那样设置一个阀值,超过后还是用拷贝,修改规则如下,maxSize 设置大小,这里阀值为 30kb 大小:

{
            test: /\.(png|svg|gif|jpe?g)$/,
            type: 'asset',
            generator:{
                filename:'img/[name].[hash:6][ext]'
            },
            parser:{
                dataUrlCondition: {
                    maxSize: 30*1024
                }
            }
        }

2.8 asset 处理字体图标:

新增如下规则:

 // 字体图标
        {
            test: /\.(ttf|woff2?)$/,
            type:'asset/resource',
            generator:{
                filename:'font/[name].[hash:3][ext]'
            },
        }

2.9 webpack 插件使用:

众所周知,插件能帮助我们更方便的做更多的事情。

2.9.1 dist 目录自动清空插件:

每次我们重新 webpack 打包的时候还要把上次打包的 dist 目录删除掉,麻烦,所以这里下载一个 dist 目录自动清空插件。以后打包会默认把上次打包内容清空后打包。

安装 clean-webpack-plugin 插件:

npm i clean-webpack-plugin -D

设置配置文件的配置项 plugins:

const path = require('path');
// 1.先导入下载的插件
const {CleanWebpackPlugin} = require('clean-webpack-plugin');


module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'build.js',
  },
  module: {。。。},
  //2.定义插件配置的属性 plugins ,存放每个插件
  plugins: [
      //3.每个插件都是一个类,直接new就行
      new CleanWebpackPlugin()
  ]
};

每个插件都是一个类,直接 new 就行,可以查看对应插件的官网,了解传的参数对应什么功能。

2.9.2 html-webpack-plugin 插件:

能帮我们打包后在打包目录里生成一个 html 文件模板,并引用入口文件。

安装 html-webpack-plugin 插件:

npm i html-webpack-plugin -D

设置配置文件的配置项 plugins:

const path = require('path');


const {CleanWebpackPlugin} = require('clean-webpack-plugin');
// 1.先导入下载的插件
const HtmlWebpackPlugin = require('html-webpack-plugin');


module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'build.js',
  },
  module: {。。。},
  plugins: [
      new CleanWebpackPlugin(),
    // 2.添加
     new HtmlWebpackPlugin()
  ]
};

webpack 打包后:

html 默认内容:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Webpack App</title>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <script defer="defer" src="build.js"></script>
  </head>
  <body></body>
</html>

对于 html 很多地方可以设置的,比如 title 的内容啥的,在配置文件 new 的时候传递对应参数就行(具体参考该插件官网):

。。。略
plugins: [
      new CleanWebpackPlugin(),
      new HtmlWebpackPlugin({
          title:'北极光之夜。'
      })
  ]

打包后生成的 html 文件内容:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>北极光之夜。</title>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <script defer="defer" src="build.js"></script>
  </head>
  <body></body>
</html>

当然,可以自己提供一个 html 模板,以我提供的模板为基础生成新的 html 模板:

1. 在 src 同级下新建一个 public 目录,在里面新建一个 index.html 文件作为模板:

2. 比如 index.html 内容如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <div class="app" id="app">test</div>
  </body>
</html>

<%= htmlWebpackPlugin.options.title %>表示使用配置里的 title。

3. 新增 template 参数,值为模板路径:

 new HtmlWebpackPlugin({
          title:'北极光之夜。',
          template:'./public/index.html'
      })

4. 打包结果:

2.10 babel-loader 处理 js 兼容:

能处理 js 兼容问题,比如兼容 es6 语法。

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

在 index.js 同级下新建一个 babel.config.js 文件专门写配置:babel.config.js 文件内容:

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

然后在 webpack.config.js 配置文件里新增规则:

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

跟在前面说到的 postcss-loader 一样,同样在.browserslistrc 文件里面写兼容的条件,如:

0.1%last 2 versionnot dead

最后 webpack 打包就行了。

2.11 polyfill 处理 js 兼容:

babel-loader 处理的 js 兼容还不够多,只能处理简单的,若存在 promise 这些新语法也不大行。所以需要 polyfill。

npm i @babel/polyfill --save

修改 babel.config.js:

module.exports = {
    presets: [
        '@babel/preset-env',
        {
            useBuiltIns: 'entry',
            crorejs: 3
        }
    ]
}

2.12 自动更新:

可以实现你修改源码后,打包后的代码也自动更新,不用每次都手动打包去更新。

1. 不使用 webpack-dev-serve 之前,可以在配置文件添加 watch 属性为 true 也能实现自动更新,但是性能不太好,不能局部更新,是一有更新就全都更新:

module.exports = {
//  这里,自动更新
    watch: true,
  //打包入口文件路径
  entry: './src/index.js',
  //path打包出口路径,filename打包后文件名
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'build.js',
    //assetModuleFilename:'img/[name].[hash:6][ext]'
  },
  。。。略
}  

2. webpack-dev-serve 性能较好,能实现局部更新,节省性能。

在终端先安装:

npm install webpack-dev-server --save-dev

以后打包命令改为:

webpack serve

2.13 HMR 模块热替换:

作用:一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块),极大的提升构建速度。

module.exports = {
  target: 'web',
  // 开启HMR
  devServer:{
      hot: true
  }
  。。。
}

然后在入口文件处通过判断给需要热更新的模块热更新:

import './title'
if(module.hot){
  module.not.accept(['./title.js'])
}

2.14 output 的 path:

output 有一个 publicPath 属性,为项目中引用 css,js,img 等资源时候的一个基础路径。其输出解析文件的目录,指定资源文件引用的目录,打包后浏览器访问服务时的 url 路径中通用的一部分。

 output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'build.js',
    publicPath:''
  },

2.15 devServer 常用配置:

devServer:{
      hot: true
      hotOnly:true,
      //默认端口
      port:4000
      //自动打开浏览器
      open:false
      //开启服务端压缩
      compress: true
      //使用 History 路由模式时,若404错误时被替代为 index.html
      historyApiFallback: true
  } 

2.16 proxy 代理:

通过 webpack 设置代理解决浏览器跨域问题。在 devServer 下添加一个 proxy 属性:

devServer:{
    ....
      proxy: {
        //定义一个标记,如以后api开头的请求都走代理的设置
          '/api': {
             // 要请求的真实服务端基地址 相当于被/api替代了
             target: 'https://...',
            //把api重写为空,因为别人没有 /api
             pathRewrite: {"^/api":""},
             //发送请求头中host会设置成target
             changeOrigin: true
          }
      }
  } 

此时,如果我们原本想请求的服务端地址为 https://… /user 就可以替换成 /api/user , 然后把/api 重写为空,那么实际上就是相当于写了 https://… /user, 如:

axios.get('/api/user').then(res=>{...})

2.17 mode 模式:

提供 mode 配置选项,告知 webpack 使用相应模式的一些内置优化。如果没有设置,webpack 会给 mode 的默认值设置为 production。

string = 'production': 'none' | 'development' | 'production'
module.exports = {
  mode: 'development',
};

2.18 打包 vue 文件:

1.安装:

$ cnpm i vue-loader vue-template-compiler -D

2.添加规则:

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

3.导入插件并使用:

const VueLoaderPlugin = require('vue-loader/lib/plugin');

未完结,持续更新中……

点击关注,第一时间了解华为云新鲜技术~

本文文字及图片出自 InfoQ


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK