webpack5 查漏补缺

Posted GoldenaArcher

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了webpack5 查漏补缺相关的知识,希望对你有一定的参考价值。

webpack5 查漏补缺

webpack5 的一些补充,其实大部分内容都已经在 [万字逐步详解]使用 webpack 打包 vue 项目(优化生产环境), [万字逐步详解]使用 webpack-dev-server + ESLint 配置 vue 项目的开发环境[万字逐步详解]使用 webpack 打包 vue 项目(基础生产环境) 里讲过了来着。

一个补充就是对于简单的练手项目,比如说建立一个 html 文件然后里面引入 js 文件这种,之前用 parcel 去初始化项目(因为不用配置),现在的话 webpack 也不需要配置了,直接下载 webpack 和 cli 之后,直接运行 npx webpack,webpack5 本身包含一些默认配置会直接运行。

相当于如果不想写配置文件,直接用个 concurrently+webpack 应该就行了……?

webpack npx webpack --stats detailed 这个 flag 可以显示更多的细节,比如:

webpack 5.75.0 compiled with 1 warning in 201 ms
➜  webpack npx webpack --stats detailed
PublicPath: auto
asset main.js 50 bytes 179 [compared for emit] [minimized] (name: main)
Entrypoint main 50 bytes = main.js
chunk 179 (runtime: main) main.js (main) 125 bytes [entry] [rendered]
  > ./src  main
orphan modules 67 bytes [orphan] 1 module
./src/index.js + 1 modules [860] 125 bytes 179 [depth 0] [built] [code generated]
  [no exports]
  [no exports used]

LOG from webpack.Compilation
    1 modules hashed, 0 from cache (0.5 variants per module in average)
    100% code generated (1 generated, 0 from cache)
+ 25 hidden lines

LOG from webpack.FlagDependencyExportsPlugin
    100% of exports of modules have been determined (0 no declared exports, 2 not cached, 0 flagged uncacheable, 0 from cache, 0 from mem cache, 0 additional calculations due to dependencies)
+ 3 hidden lines

LOG from webpack.buildChunkGraph
    4 queue items processed (2 blocks)
    0 chunk groups connected
    0 chunk groups processed for merging (0 module sets, 0 forked, 0 + 0 modules forked, 0 + 0 modules merged into fork, 0 resulting modules)
    0 chunk group info updated (0 already connected chunk groups reconnected)
+ 5 hidden lines

LOG from webpack.FileSystemInfo
    2 new snapshots created
    0% root snapshot uncached (0 / 0)
    0% children snapshot uncached (0 / 0)
    0 entries tested
    File info in cache: 2 timestamps 2 hashes 2 timestamp hash combinations
    File timestamp hash combination snapshot optimization: 0% (0/2) entries shared via 0 shared snapshots (0 times referenced)
    Directory info in cache: 0 timestamps 0 hashes 0 timestamp hash combinations
    Managed items info in cache: 0 items

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value.
Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

2023-01-06 17:49:32: webpack 5.75.0 compiled with 1 warning in 188 ms (776711aca0a0d983099b)

没有配置文件的话,index.js 是默认的 entry, main.js 是默认的输出文件。

以及 git repo: https://github.com/GoldenaArcher/webpack5-study-case

asset

asset 分为四种:

  • asset/resource

    这个配置生成的文件是 hashed 值+原有的扩展名

    const path = require('path');
    
    module.exports = 
      entry: './src/index.js',
      output: 
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist/'),
      ,
      mode: 'none',
      module: 
        rules: [
          
            test: /\\.(png|jpg)$/,
            // either type or use
            type: 'asset/resource',
          ,
        ],
      ,
    ;
    

    import Lion from './lion_PNG3809.png';
    
    export const addImage = () => 
      const img = document.createElement('img');
      img.src = Lion;
      const body = document.querySelector('body');
      body.appendChild(img);
    ;
    
  • asset/inline

    使用 inline 会将文件打包成 inline(行内)资源,而不是额外成生一个文件。

  • asset

    webpack 自行决定配置,小于 8kb 的自动压缩成 inline,大于 8kb 的则额外成成一个文件,这也解释了我之前的一个小疑惑:

    不过说起来,vue 的 logo 正好卡在 8kb 这个尺寸,所以这大概是有什么约定俗成的规矩的?

    当然,配置的大小可改,大致如下:

    const path = require('path');
    
    module.exports = 
      entry: './src/index.js',
      output: 
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist/'),
        // default for webpack5: publicPath: 'auto'
        // default for webpack4: publicPath: ''
        publicPath: 'dist',
      ,
      mode: 'none',
      module: 
        rules: [
          
            test: /\\.(png|jpg)$/,
            // either type or use
            type: 'asset',
            parser: 
              dataUrlCondition: 
                maxSize: 8 * 1014, // default value
              ,
            ,
          ,
        ],
      ,
    ;
    
  • asset/source

    将引入的文件保存成一个 js 变量进行存储,如下面引入了一个 txt 文件,并且将其设置成图片的 alt text:

    import Lion from './lion_PNG3809.png';
    import alt from './randomText.txt';
    
    export const addImage = () => 
      const img = document.createElement('img');
      img.src = Lion;
      img.alt = alt;
      img.width = '200';
      const body = document.querySelector('body');
      body.appendChild(img);
    ;
    

缓存文件

[万字逐步详解]使用 webpack 打包 vue 项目(优化生产环境) 有说,直接在文件名中加入 [contenthash:bit] 即可,如 bundle.[contenthash:8].js

devServer

[万字逐步详解]使用 webpack 打包 vue 项目(优化生产环境) 基本有讲,这里补充一下,如果 hot: true 没有设置的话,可以在脚本 npx server ... --hot 中设置,除此之外 devServer 还有一个配置看了一下,也许也挺有用的:


    devMiddleware: 
      index: 'index.html',
      writeToDisk: true,    // by default is false
    ,

loaders

loaders 和 plugins 的区别,来自 stack overflow:

Loaders:

Loaders work at the individual file level during or before the bundle is generated.

Plugins:

Plugins work at bundle or chunk level and usually work at the end of the bundle generation process. Plugins can also modify how the bundles themselves are created. Plugins have more powerful control than loaders.

大致说就是 loader 负责处理打包之前的代码,plugin 处理在打包时或是打包后的代码,并且 plugin 的功能逼 loader 强。

CSS loader

CSS loader: [万字逐步详解]使用 webpack 打包 vue 项目(基础生产环境)

for SASS/SCSS, install sass-loader and sass:

Babel loader

[万字逐步详解]使用 webpack 打包 vue 项目(基础生产环境) 也有讲,不过当时主要处理的是 vue 相关的,这里就处理一些……浏览器不能编译的代码吧。

运行最新版本的 js 代码(在 proposal 中的)需要额外下载对应的 babel plugin,我这里下载的 babel 相关依赖包含::

  • “@babel/cli”: “^7.20.7”,
  • “@babel/core”: “^7.20.12”,
  • “@babel/plugin-proposal-decorators”: “^7.20.7”,
  • “@babel/plugin-proposal-pipeline-operator”: “^7.18.9”,
  • “@babel/preset-env”: “^7.20.2”,

下面是浏览器目前不能运行的代码,一个是 decorator,一个是 pipeline operator:

function add(x) 
  return x + 10;


function subtract(x) 
  return x - 5;


// Without pipeline operator
let val1 = add(subtract(add(subtract(10))));
console.log(val1);

// Using pipeline operator

// First 10 is passed as argument to subtract
// function then returned value is passed to
// add function then value we get is passed to
// subtract and then the value we get is again
// passed to add function
let val2 = 10 |> subtract |> add |> subtract |> add;
console.log(val2);

@annotation
class MyClass 

function annotation(target) 
  target.annotated = true;

有可能当你看到这段代码的时候,这个也被加到 babel 里了

截止 2023 年 1 月时,这个运行时失败的:

webpack 对应的部分:

module.exports = 
    // ...
      
        test: '/.js$/',
        exclude: /node_modules/,
        use: 
          loader: 'babel-loader',
        ,
      ,

目前的版本对接了 babel-loader 之后,webpack 可以自动找 babelrc 文件进行配置,并且 babelrc 会重写 webpack 的配置:

这里报错报到我真的想离开这部分不管了……


  "plugins": [
    [
      "@babel/plugin-proposal-pipeline-operator",
       "proposal": "minimal", "topicToken": "^^" 
    ],
    ["@babel/plugin-proposal-decorators",  "legacy": true ]
  ]

一些配置还是要官网和 stack overflow 混着来,目前来说 decorator 不用 legacy 的话,我本地暂时还没办法跟着官方文档跑起来……

plugins

TerserPlugin

这个插件 v5 已经自动安装了,不需要额外下载,另外生产模式默认开启这个,可以不用额外配置。差别大概是这样的:

minimize CSS

[万字逐步详解]使用 webpack 打包 vue 项目(优化生产环境) 有说,用的是 mini-css-extract-plugin

这个插件抽取 CSS,并且单独放到另一个 CSS 文件里。

每次打包清除已经构建的文件

[万字逐步详解]使用 webpack 打包 vue 项目(基础生产环境) 有讲,用 clean-webpack-plugin 即可。

另外 5.20 以上可以使用 output.clean (webpack 自带),如:


  output: 
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist/'),
    // default for webpack5: publicPath: 'auto'
    // default for webpack4: publicPath: ''
    publicPath: 'dist/',
    // ⬇️
    clean: true,
  ,

clean 还有更多的配置,具体可以参考:output.clean,不过这个实现的功能比较少,如果需求只是删除部分文件,或是 dist 下的所有文件,使用自带的 clean 即可。

自动生成 HTML 文件

文件一旦打了哈希值后,目前 HTML 文件就没办法自动追踪新生成的文件,[万字逐步详解]使用 webpack 打包 vue 项目(基础生产环境) 有讲,使用的插件为 htmlWebpackPlugin。

默认配置下 htmlWebpackPlugin。只会新建一个 HTML 文件建立 webpack 打包好的文件之间的引用,不会 cv 原本 html 文件的内容,所以之前的项目会用 template 这个参数将对应的 HTML 文件作为模板进行 cv。

这里使用另一个模板文件作为案例:

这里使用的模板文件是 hbs(也可以用 ejs 之类的),hbs 文件如下:

<html>
  <head>
    <meta charset='utf-8' />
    <title>htmlWebpackPlugin.options.title</title>
    <meta
      name='description'
      content='htmlWebpackPlugin.options.description'
    />
    <meta name='viewport' content='width=device-width, initial-scale=1' />
  </head>
  <body>
  </body>
</html>

webpack 的配置如下:

new HtmlWebpackPlugin(
  template: 'src/index.hbs',
  title: 'Title from HBS',
  description: 'description loaded from template file',
);

配置完了之后,htmlWebpackPlugin 就会以 hbs 文件作为模板,同时从 HtmlWebpackPlugi 拉对应的值进行诸如。

Reference

以上是关于webpack5 查漏补缺的主要内容,如果未能解决你的问题,请参考以下文章

webpack5 - 查漏补缺 2

webpack5 - 查漏补缺 2

微前端之 Webpack5 的 module federation

微前端之 Webpack5 的 module federation

查漏补缺1

JavaScript查漏补缺 —数组中reduce()方法