Webpack打包其他资源

240 阅读4分钟

Webpack 打包其他资源

file-loader

  • 要处理 jpg、png 等格式的图片,需要有对应的 loader :file-loader

    • file-loader 的作用就是帮助我们处理 import/require() 方式引入的一个文件资源,并且会将它放到我们 输出的文件夹中;
  • 安装 file-loader:

    npm install file-loader -D

  • 配置处理图片的 Rule:

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

文件的命名规则

  • 我们处理后的文件名称需要按照一定的规则进行显示:

    • 比如保留原来的文件名、拓展名,同时为了防止重复,包含一个 hash 值等;
  • 可以使用 PlaceHolders 来完成, webpack 给我们提供了大量的 PlaceHolder 来显示不同的内容:
  • 常用的 PlaceHolder:

    • [ext] : 处理文件的拓展名;
    • [name] : 处理文件的名称;
    • [hash] : 文件的内容,使用 MD4 的散列函数处理,生成一个 128 位的 hash (32 个十六进制);
    • [contentHash] :在 file-loader 中和 [hash] 结果一致;
    • [hash: < length >] : 截取 hash 的长度,默认 32个 字符太长了;
    • [path] : 文件相对于 webpack 配置文件的路径;

设置文件的名称与路径

   {
    test: /.(jpe?g|png|gif|svg)$/,
    use: {
         loader: 'file-loader',
             options: {
               // 此处前面加 img/ 已经设置了路径,也可通过 outputPath 来设置输出的文件夹;
               name: 'img/[name].[hash:8].[ext]',
               // outputPath:'img',
             }
         }
   }

url-loader

  • url-loader 和 file-loader 的工作方式是相似的,但可以将较小的文件,转成 base64 的 URI。
  • 安装 url-loader:

    npm install url-loader -D

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

url-loader 的 limit

  • 开发中往往需要将小的图片进行转换,大的图片直接使用;

    • 因为小的图片转换 base64 之后可以和页面一起被请求,减少不必要的请求过程;
    • 而大的图片也进行转换反而会影响页面的请求速度;
  • 限制大小用于判断图片需不需要进行转换:

    • url-loader 的 options 属性 limit,可以用于设置转换的限制;
   {
    test: /.(jpe?g|png|gif|svg)$/,
    use: {
         loader: 'url-loader',
             options: {
             limit: 100*1024,
             name: 'img/[name].[hash:8].[ext]',
             }
         }
   }

认识 asset module type(资源模块类型)

  • 从 Webpack5 开始,我们可以直接使用资源模块类型,来代替一些 loader;
  • 通过添加 4 种新的模块类型,来替换这些 loader:

    • asset/resource 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现;
    • asset/inline 导出一个资源的 data URI。之前通过使用 url-loader 实现;
    • asset/source 导出资源的源代码。之前使用 raw-loader 实现;
    • asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现;

加载字体文件

  • 如果我们需要使用某些特殊的字体或者字体图标,那么我们会引入很多字体相关的文件;
  • 在 component 中引入,使用 i 元素显示字体图标:
// i元素
const iEl = document.createElement("i");
iEl.className = "iconfont icon-ashbin";
document.body.appendChild(iEl);

字体的打包

使用 webpack5 的资源模块类型来处理;

      {
        test: /.(eot|ttf|woff2?)$/,
        type: "asset/resource",
        generator: {
          filename: "font/[name]_[hash:6][ext]",
        },
      },

认识 Plugin

  • Loader 适用于特定的模块类型进行转换;
  • Plugin 可以用于执行更加广泛的任务,比如打包优化、资源管理、环境变量注入等;

CleanWebpackPlugin

  • 之前每次修改配置重新打包时,都需要手动删除 dist 文件夹;

    • 我们可以借助于一个插件来帮助我们完成,即 CleanWebpackPlugin;
  • 安装插件:

    npm install clean-webpack-plugin

  • 在插件中配置

    const { CleanWebpackPlugin } = require("clean-webpack-plugin");
    module.export = {
        plugins: [
            new CleanWebpackPlugin(),
        ]
    }
    

HtmlWebpackPlugin

对 HTML 进行打包处理:

const HtmlWebpackPlugin = require("html-webpack-plugin");
module.export = {
    plugins: [
        new HtmlWebpackPlugin(),
    ]
}

自定义模板数据填充

  • 在配置 HtmlWebpackPlugin 时,可以添加如下配置:

    • template:指定我们要使用的模块所在路径;
    • title:在进行 HtmlWebpackPlugin.options.title 读取时,会读到该信息;
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.export = {
    plugins: [
        new HtmlWebpackPlugin({
            title: 'webpack项目',
            template: './public/index.html'
        }),
    ]
}

CopyWebpckPlugin

  • 在 Vue 打包过程中,如果我们将一些文件放到 public 的目录下,这个目录会被赋值到 dist 文件夹中,这个功能可以使用 CopyWebpackPlugin 来完成;

  • 安装 CopyWebpackPlugin 插件:

    npm install copy-webpack-plugin -D

  • 配置 CopyWebpackPlugin :

    • 复制的规则在 patterns 中设置;
    • from:设置从哪一个源中开始复制;
    • to:复制到的位置,可省略,会默认复制到打包目录下;
    • gloOptions:设置一些额外的选项,其中可以编写需要忽略的文件;
     new CopyWebpackPlugin({
       patterns: [
         {
           from: "public",
           gloOptions: {
             ignore: ["**/index.html"],
           },
         },
       ],
     }),

Mode 和 Devtool 配置

module.exports = {
  // 设置模式
  // 开发阶段,会设置development
  // production 准备打包上线的时候,设置prodution
  mode: "development",
  // 设置source-map,建立js映射文件,方便调试代码和错误
  devtool: "source-map",
}

为什么需要babel

  • 在开发中很少直接去使用 babel,但是 babel 对于前端开发来说是不可或缺的一部分:

    • 使用 ES6+ 的语法, TypeScript和开发 React 项目,它们都是离不开 babel 的;
    • babel 可以让我们理解代码从编写到线上的转变;
  • babel 的含义

    • babel 是一个工具链,主要用于旧浏览器或者环境中将 ECMAScript + 代码转换为向后兼容版本的 JavaScript;
    • 包括:语法转换、源代码转换等;
[1,2,3].map((n) => n + 1);
​
[1,2,3].map(function(n)) {
return n + 1;
}

babel 命令行使用

  • babel 本身可以作为一个独立的工具(和 postcss 一样),不和 webpack 等构建工具配置来单独使用。

  • 需要安装如下库:

    • @babel/core:babel 的核心代码,必须安装;
    • @babel/cli:可以让我们在命令行使用 babel;

安装指令: npm install @babel/cli @babel/core -D

  • 使用 babel 来处理源代码:

    • src:源文件的目录;
    • --out-dir:指定要输出的文件夹 dist;

指令: npx babel src --out-dir dist

插件的使用

  • 若需要转换箭头函数,可以使用相关插件来完成;

指令: npm install @babel/plugin-transform-arrow-functions -D

npx babel src --out-dir dist --plugins=@babel/plugin-transform-arrow-functions

  • 使用后 const 并没有转换成 var;

    • 因为 plugin-transform-arrow-functions,并没有提供这样的功能;
    • 需要使用 plugin-transform-block-scoping 来完成这样的功能;

指令: npm install @babel/plugin-transform-block-scoping -D

npx babel src --out-dir dist --plugins=babel/plugin-transform-block-scoping,@babel/plugin- transform-arrow-functions

babel 的预设 preset

  • 如果需要转换的内容过多,可以使用预设(preset);

  • 安装 @babel/preset-env 预设:

    npm inatall @babel/preset-env -D

  • 执行如下命令:

    npx babel src --out-dir dist --persets=@babel/preset-env

babel 的底层原理

  • 本质上来说,babel 就是一个编译器,将一种源代码转换为另一种源代码;

  • 工作流程:

    • 解析阶段(Parsing);
    • 转换阶段(Transformation);
    • 生成阶段(Code Generation);

babel-loader

  • 在实际开发中,通常会在构建工具中通过配置 babel 来对其进行使用,如 webpack ;

  • 需要安装相关的依赖:

    • 如果之前已经安装了 @babel/core, 那么不需要再次安装;

      npm install babel-loader @babel/core

  • 可以设置一个规则,在加载 js 文件时,使用 babel;

module: {
    rules: [
        {
            test: /.m?js$/,
            use: {
                loader: 'babel-loader',
            }
        }
    ]
}

指定使用的插件

{
    test: /.m?js$/,
    use: {
        loader: 'babel-loader',
        options: {
          plugins: [
              '@babel/plugin-transform-block-scoping',
              '@babel/plugin-transform-arrow-functions'
          ]       
    }
  }
}

babel 的配置文件

  • 可以将 babel 的配置信息放到一个独立的文件中,babel 给我们提供了两种配置文件的编写:

    • babel.confih.json(或 .js, .cjs, .mjs)文件;
    • .babelrc.json(或 .babelrc, .js, .cjs, .mjs)文件; (更加推荐)

搭建本地服务器

  • 目前开发的代码,为了运行需要有两个操作:

    • 操作一:npm run build;
    • 操作二:通过 live server 或者直接通过浏览器,打开 index.html 代码,查看效果;
  • 这个过程会影响我们开发效率,我们希望当文件发生变化时,可以自动地完成编译和展示

  • 为了完成自动编译,webpack 提供了几种可选的方式:

    • webpack watch mode;
    • webpack-dev-server(常用);
    • webpack-dev-middleware;

Webpck watch

  • webpack 给我们提供了 watch 模式:

    • 在该模式下,webpack 依赖所有文件,只要有一个发生了更新,代码将被重新编译;
    • 不需要手动运行 npm run build 指令了;
  • 开启 watch 的方式:

    • 方式一:在导出的配置中,添加 watch:true;
    • 方式二:在启动 webpack 命令中,添加 --watch 的标识;
  • 方式二:在 packag.json 的 scripts 中添加一个 watch 的脚本:

"scripts": {
    "build": "webpack --config wk.config.js",
    "watch": "webpack --watch",
    "type-check": "tsc --noEmit",
    "type-check-watch": "npm run type-check -- --watch"
},

webpack-dev-server

  • watch 方式可以监听到文件的变化,但是事实上它本身是没有自动刷新浏览器功能的:

    • 是通过z在 VSCode 中使用 live-server 来完成这样的功能的;
    • 我们希望在不使用 live-server 的情况下,可以具备 live reloading (实时重新加载) 的功能;
  • 安装 webpack-dev-server

    npm install webpack-dev-server -D

  • 修改配置文件,告知 dev server,从什么位置查找文件:

devServer: {
    contentBase: "./build"
},
target: "web",
"serve": "webpack serve --config wk.config.js"
  • webpack-dev-server 在编译之后不会写入到任何输出文件,而是将 bundle 文件保留在内存中:

    • 事实上 webpack-dev-server 使用了一个库叫 memfs(memory-fs webpack 自己写的)

模块热替换(HMR)

  • HMR 的定义

    • HMR 的全称是 Hot Module Replacement;
    • 模块热替换是指在应用程序运行过程中,替换、添加、删除模块。而无需重新刷新整个页面;
  • HMR 通过如下几种方式,来提高开发的速度:

    • 不重新加载整个页面,可以保留某些应用程序的状态不丢失;
    • 只需要更新变化的内容,节省开发的时间;
    • 修改了 css、js 源代码,会立即在浏览器更新,相当于直接在浏览器的 devtools 中直接修改样式;
  • 使用 HMR

    • 默认情况下,webpack-dev-server 已经支持 HMR,我们只需要开启即可;
    • 在不开启 HMR 的情况下,当我们修改了源代码之后,整个页面会自动刷新,使用的是 live reloading;

HMR 的原理

HMR Socket Server,是一个 socket 的长连接:

  • 长连接建立后双方可以通信(服务器可以直接发送文件到客户端);
  • 当服务器监听到对应的模块发生变化时,会生成两个文件:.json(mainifest 文件)和 .js 文件(update chunk);'
  • 通过长连接,可以直接将这两个文件主动发送给客户端(浏览器);
  • 浏览器拿到两个新的文件后,通过 HMR runtime 机制,加载这两个文件,并且针对修改的模块进行更新; \