webpack提示效率-如何利用webpack提高后端开发效率(二)?

2024-04-27 0 3,599 百度已收录

通过学习如何使用webpack提高后端开发效率(一),我们已经可以通过webpack的loader和piugin机制处理各种文件资源了。细心小伙伴发现缺少字体文件和HTML支持

标签资源处理,那么我们就先解决这个问题

接下一篇文章,我们的目录结构如图

首先是处理字体文件,更改webpack.config.js

// webpack.config.js
// 新增对字体的loader
      {
        test: /.(eot|woff|woff2|ttf)$/,
        use: [{
          loader: 'url-loader',
          options: {
            name: '[name].[hash:7].[ext]',
            limit: 8192,
            outputPath: 'font',  // 打包到 dist/font 目录下
          }
        }]
      },
复制代码

如何从网上随机下载一个字体,放到src文件夹下,并修改src/index.html




  
  
  
  my-webpack


  

webpack大法好!!前端大法好!!

复制代码

在index.scss引入字体

/* src/index.scss */
/* 添加以下样式 */
@font-face {
  font-family: 'myFont';
  src: url('./font/ZaoZiGongFangQiaoPinTi-2.ttf');
}
h1 {
  font-family: 'myFont';
}
复制代码

之前每次重新打包的时候都要删除dist文件夹,确实很麻烦。 现在我们可以使用clean-webpack-plugin,它也可以在每次打包时删除指定的文件夹。 我们在命令行执行npmiclean-webpack-plugin-D

更改 webpack.config.js

// webpack.config.js
// 新增以下引入
const CleanWebpackPlugin = require('clean-webpack-plugin');
// 新增以下插件
plugins: [
    new CleanWebpackPlugin(['dist'])
],
复制代码

然后在命令行执行npmrunbuild,我们的dist文件夹就会被手动删除,并输出如下结果。 可以看到,虽然我们成功打包了字体文件,但是字体文件太大了,甚至webpack发出警告 [big] 。

这里我们通常有以下几种解决方案

CDN
font-spider

我们来练习第三种方案,这也是我推荐的方案。 在命令行中依次执行。

npm i font-spider -D
font-spider ./dist/index.html
复制代码

可以看到近4MB的字体文件大小压缩到了6KB以下! ! ! 页面效果和之前一模一样。

对于 HTML 文档

webpack提示效率-如何利用webpack提高后端开发效率(二)?

对于标签的引入,我们需要使用html-loader,它可以将HTML文档中的img.src解析为require,这样就可以引入图片了。 废话不多说,我们直接看一下功效。 在命令行执行npmihtml-loader -D

更改以下文件

// webpack.config.js
// 新增对html的loader
      {
        test: /.html$/,
        use: {
          loader: 'html-loader',
          options: {
            attrs: ['img:src'] // img代表解析标签,src代表要解析的值,以key:value形式存在于attrs数组中
          }
        }
      }
复制代码


    +  

复制代码

在命令行执行npmrunbuild并检查dist/index.html。 看来已经成功了。

动态加载

想象一下,如果我们的入口文件很大(包括所有业务逻辑代码),就会导致首屏加载缓慢,用户体验下降。 这里我们从两个方面来解决:

// dynamic.js
export default () => {
  console.log('Im dynamically loaded.');
}
复制代码

更改以下文件


  + 

复制代码

// src/index.js
// 新增以下内容
const btn = document.getElementById('btn');
// 点击按钮,动态加载dynamic.js
btn.onclick = () => {
  import(/* webpackChunkName: "dynamic" */ './dynamic.js').then(function (module) {
    const fn = module.default;
    fn();
  })
}
复制代码

执行npmrunbuild可以看到

如果 /*webpackChunkName:"dynamic"*/ 未设置

,那么就是

可以得出推论是,必须将ChunkName设置为“dynamic”,否则该包将是一个以手动分配的id命名的JS文件,可读性很差。 并且没有 ChunkNames

标记

现在我们打开dist/index.html,此时

当我点击按钮时

控制台复制出来

Network网络请求显示dynamic.js是动态加载的

至此,我们就成功实现了动态加载。

开发环境生产环境分开

回头看看我们的webpack.config.js,我们不知不觉写了这么多代码。 考虑到我们在开发实际项目时,有两种工作模式:开发和生产,各司其职。 我们不妨打断一下,把配置分开。 。

命令行执行 npmiwebpack-mergecross-env -D

webpack-merge 可以合并 webpack 配置项,cross-env 可以设置和使用环境变量

添加了 webpack.base.js 以提供基本的 webpackloaderplugin 配置

const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const pathResolve = (targetPath) => path.resolve(__dirname, targetPath);
const devMode = process.env.NODE_ENV !== 'production';
// 在node中,有全局变量process表示的是当前的node进程。
// process.env包含着关于系统环境信息。
// NODE_ENV是用户一个自定义的变量,在webpack中它的用途是来判断当前是生产环境或开发环境。
// 我们可以通过 cross-env 将 NODE_ENV=development 写入 npm run dev的指令中,从而注入NODE_ENV变量。
module.exports = {
  entry: {
    index: pathResolve('js/index.js')
  },
  output: {
    path: pathResolve('dist'),
  },
  module: {
    rules: [
      {
        test: /.html$/,
        use: {
          loader: 'html-loader',
          options: {
            attrs: ['img:src']
          },
        },
      },
      {
        test: /.(eot|woff|woff2|ttf)$/,
        use: [{
          loader: 'url-loader',
          options: {
            name: '[name].[hash:7].[ext]',
            limit: 8192,
            outputPath: 'font',
          },
        }],
      },
      {
        test: /.(sa|sc|c)ss$/,
        use: [
          devMode ? 'style-loader' : {  // 如果处于开发模式,则无需外链CSS,直接插入到标签中
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '../'
            }
          },
          'css-loader',
          'postcss-loader',
          'sass-loader',
        ],
      },
      {
        test: /.(png|jpg|jpeg|svg|gif)$/,
        use: [{
          loader: 'url-loader',
          options: {
            limit: 8192,
            name: '[name].[hash:7].[ext]',
            outputPath: 'img',
          },
        }],
      },
    ],
  },
  plugins: [
    new htmlWebpackPlugin({
      minify: {
        collapseWhitespace: true,  // 移除空格
        removeAttributeQuotes: true, // 移除引号
        removeComments: true // 移除注释
      },
      filename: pathResolve('dist/index.html'),
      template: pathResolve('src/index.html'),
    })
  ]
};
复制代码

添加了 webpack.dev.js 以在开发模式下提供服务

const path = require('path');
const webpack = require('webpack');
const base = require('./webpack.base.js');
const { smart } = require('webpack-merge');
const pathResolve = (targetPath) => path.resolve(__dirname, targetPath);
module.exports = smart(base, {
  mode: 'development',
  output: {
    filename: 'js/[name].[hash:7].js'
  },
  devServer: {
    contentBase: pathResolve('dist'),
    port: '8080',
    inline: true,
    historyApiFallback: true,
    hot: true
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin()
  ]
})
复制代码

添加了 webpack.prod.js 以在生产模式下提供服务

const path = require('path');
const base = require('./webpack.base.js');
const { smart } = require('webpack-merge');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const pathResolve = (targetPath) => path.resolve(__dirname, targetPath);
module.exports = smart(base, {
  mode: 'production',
  devtool: 'source-map', // 会生成对于调试完整的.map文件,但同时也会减慢打包速度,适用于打包后的代码查错
  output: {
    filename: 'js/[name].[chunkhash:7].js',
    chunkFilename: 'js/[name].[chunkhash:7].js',
  },
  plugins: [
    new CleanWebpackPlugin(['dist']),
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:7].css',
    }),
  ],
});
复制代码

相应的,package.json也需要更改。

// 新增以下两条命令
// cross-env 决定运行环境   --config 决定运行哪个配置文件
"dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.dev.js",
"build": "cross-env NODE_ENV=production webpack --config webpack.prod.js "
复制代码

缓存之战

后端缓存状态是毋庸置疑的。 正确使用缓存可以大大提高应用程序的加载速度和性能。 Webpack使用哈希值作为文件名的一部分,可以有效地利用缓存。 当文件发生更改或者重新打包时,哈希值会发生变化,导致缓存失效,HTTP请求重新拉取资源。

Webpack 有三种哈希处理策略,分别是:

散列

webpack提示效率-如何利用webpack提高后端开发效率(二)?

属于项目级别,即任何一个文件每次发生变化,所有文件名的哈希值都会发生变化。 所以一旦任何一个文件发生改变,整个项目的文件缓存就会失效。 例如,如果将整个项目的文件名的命名策略改为name.[hash:7](:7表示截取完整哈希值的前七位),我们可以看到该文件的哈希值打包后的文件是一样的,所以对于没有改变的模块来说,hash也被更新了,导致缓存失效。

块哈希

Chunkhash根据不同的入口文件(Entry)解析依赖文件,构建对应的chunk,并生成对应的hash值。 例如,如果将整个项目文件名的命名策略改为name.[chunkhash:7],我们可以看到ChunkNames为“index”的文件具有相同的hash值webpack提示效率,但不同的chunk具有不同的hash值。 这也防止了更改某个文件会改变整个项目的哈希值的情况

内容哈希

但问题突然出现了。 index.scss作为模块导出到index.js,其chunkhash值一致。 只要其中之一发生变化,其关联文件的 chunkhash 值也会发生变化。 这个时候就要用到contenthash了。 根据文件内容估计。 如果文件内容发生变化,contenthash 值也会发生变化。 我们将css文件的命名策略更改为name.[contenthash:7],并更改了src/index.jswebpack提示效率,其他文件没有更改。 我们再次打包发现:

生产环境tree-shaking的配置优化

字面意思就是把树上的叶子抖落下来,使数字的重量减轻。 类比程序,就像从我们的应用程序中删除无用的代码,从而减少体积。 得益于ES6中对模块引入的静态分析,webpack能够在编译时正确判断加载哪些代码,即没有引用的模块不会被打包,减少了我们的包大小,缩短了应用加载时间,并呈现给用户更好的体验。 如何使用它?

创建新的 src/utils.js

// src/utils.js
const square = (num) => num ** 2;
const cube = num => num * num * num;
// 导出了两个方法
export {
  square,
  cube
}
复制代码

创建新的 src/shake.js

// src/shake.js
import { cube } from './utils.js';
// 只使用了cube方法
console.log('cube(3) is' + cube(3));
复制代码

在webpack.base.js中添加入口文件shake.js

entry: {
    +  shake: pathResolve('src/shake.js')
  },
复制代码

在命令行执行npmrunbuild,查看打包好的shake.js,发现square方法没有打包,说明tree-shaking起作用了。 而这一切都是由webpack在生产环境中手动为我们实现的。

分割

字面意思就是分割代码块。 默认情况下,它只会影响按需加载的代码块,因为更改初始化的代码块将影响运行项目时需要包含的 HTML 中的脚本标签。 请记住,我们在 src/index.js 中动态引入了 src/dynamic.js。 最终,dynamic.js 被独立打包了,这要归功于 splitChunks

在实际生产中,我们经常引入第三方库(JQuery、Lodash)。 往往这些第三方库的体积高达几十KB,与业务代码混合在一起,而且它们的更新频率不如业务代码。 这时,我们需要将它分离出来,不仅可以维护第三方库的持久化缓存,还可以减少业务代码的大小。

更改 webpack.prod.js

// 在module.exports中新增如下内容
  optimization: {
    runtimeChunk: {
      name: 'manifest', // 被注入了webpackJsonp的定义及异步加载相关的定义,单独打包模块信息清单利于缓存
    },
    splitChunks: {
      cacheGroups: { // 缓存组,默认将所有来源于node_modules的模块分配到叫做'venders'的缓存组,所有引用超过两次的模块分配到'default'缓存组.
        vendor: {
          chunks: "all",                    // all, async, initial 三选一, 插件作用的chunks范围,推荐all
          test: /[\/]node_modules[\/]/,   // 缓存组所选择的的模块范围
          name: "vendor",                   // Chunk Names及打包出来的文件名
          minChunks: 1,                     // 引用次数>=1
          maxInitialRequests: 5,            // 页面初始化时加载代码块的请求数量应该<=5
          minSize: 0,                       // 代码块的最小尺寸
          priority: 100,                    // 缓存优先级权重
        },
      }
    }
  },
复制代码

命令行执行 npmilodash -S

更改 src/index.js

// 新增以下内容
import _ from 'lodash';
复制代码

执行npmrunbuild,可以看到优化前lodash被打包到index.js中,优化后lodash被打包到vendor.js中。

压缩代码并去除冗余

通常在 CSS 代码中,有很多样式是我们不使用的。 它们是多余的。 我们需要删除它们并压缩剩余的 CSS 样式以减小 CSS 文件的大小。

在命令行执行 npmigloboptimize-css-assets-webpack-pluginpurifycss-webpackpurify-css-D

更改 webpack.prod.js

// 新增以下引入
const glob = require('glob'); // 匹配所需文件
const PurifyCssWebpack = require('purifycss-webpack'); // 去除冗余CSS
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); // 压缩CSS
// 新增以下插件
new PurifyCssWebpack({
    paths: glob.sync(pathResolve('src/*.html')) // 同步扫描所有html文件中所引用的css,并去除冗余样式
})
// 新增以下优化
optimization: {
    minimizer: [
      new OptimizeCSSAssetsPlugin({}) // 压缩CSS
    ]
  }
复制代码

执行npmrunbuild

正如您所看到的,不仅删除了多余的 CSS,而且将其压缩为一行。 接下来,我们需要压缩JS代码。 因为我们使用的是uglifyjs-webpack-plugin

,它需要ES6支持,所以我们首先让项目支持ES6句型。 Babel 是一个 JavaScript 编译器。 它可以将下一代JavaScript句型翻译成ES5,以适应各种运行环境。

@babel/core 提供 babel 的翻译 API,例如 babel.transform 等,用于翻译代码。 就像 webpack 的 babel-loader 一样,它调用这些 API 来完成翻译过程

@babel/preset-env 可以根据配置的目标浏览器或运行环境手动将 ES2015+ 代码转换为 ES5。

首先在命令行执行npmi@babel/core@babel/preset-envbabel-loader@babel/plugin-syntax-dynamic-import-D

创建一个新的 .babelrc 文件

{
  "presets": [  // 配置预设环境
    ["@babel/preset-env", {
      "modules": false
    }]
  ],
  "plugins": [
    "@babel/plugin-syntax-dynamic-import" // 处理src/index.js中动态加载
  ]
}
复制代码

webpack提示效率-如何利用webpack提高后端开发效率(二)?

更改 webpack.base.js

// 新增js的解析规则
    {
        test: /.(js|jsx)$/,
        use: 'babel-loader',
        exclude: /node_modules/
    },
复制代码

然后在命令行执行npmiuglifyjs-webpack-plugin -D

更改 webpack.prod.js

// 新增以下引入
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
// 新增以下优化
optimization: {
    minimizer: [
    +  new UglifyJsPlugin({ // 压缩JS
        cache: true,
        parallel: true,
        sourceMap: true
      })
    ]
  }
复制代码

执行npmrunbuild,可以看到打包后的文件大小大大减小。 大功告成,JS也被压缩了。

以index.html为例,我们可以打开Chrome的开发者工具,选择Moretools,点击Coverage面板,可以看到JS、CSS等文件的使用情况,可以通过我们自定义的webpack配置进行优化。

多页

有时,我们需要同时创建多个页面。 使用html-webpack-plugin,我们只需要在plugins中添加新页面的配置项即可。

添加了 src/main.html



  
  
  
  main page


  

I am Main Page

复制代码

更改 webpack.base.js

// 修改以下内容
  plugins: [
    new htmlWebpackPlugin({ // 配置index.html
      minify: {
        collapseWhitespace: true,
        removeAttributeQuotes: true,
        removeComments: true
      },
      filename: pathResolve('dist/index.html'),
      template: pathResolve('src/index.html'),
      chunks: ['manifest', 'vendor', 'index', ]  // 配置index.html需要用的chunk块,即加载哪些JS文件,manifest模块管理核心,必须第一个进行加载,不然会报错
    }),
    new htmlWebpackPlugin({ // 配置main.html
      minify: {
        collapseWhitespace: true,
        removeAttributeQuotes: true,
        removeComments: true
      },
      filename: pathResolve('dist/main.html'),
      template: pathResolve('src/main.html'),
      chunks: ['manifest', 'shake'] // 配置index.html需要用的chunk块,加载manifest.js,shake.js
    }),
  ],
复制代码

执行npmrunbuild并成功创建index.html和main.html。

结论

至此,我们摆脱了第三方脚手架束缚,逐步构建了自己的后端流程工具,达到了即用型、功能齐全快捷方便、可复用性高的特点。 希望男伴能自己动手,不要总是纸上谈兵的webpack,一定要了解它的建立和优化原理,并融入到自己的工程项目中,拒绝使用以前复杂的、不规范开发流程,不做“CV工程师”,创建自己的知识体系和工作流程,提高后端开发效率。

最后,这个项目源码已经部署在Github上,额外做了很多优化(少支持、ESLint检查、图片格式压缩……),方便大家直接下载体验,辅助项目开发。 以后持续维护,希望男伙伴们互相学习,提出建议

easy-frontend是一款快速简单、易用的后端开发效率提升工具

Star计划是大家对我最大的鼓励! ! 后端不忘初心,祝您早日致富! !

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 webpack webpack提示效率-如何利用webpack提高后端开发效率(二)? https://www.wkzy.net/game/201400.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务