Webpack详情2

引入 lesssassscss)、stylus

less sass scss stylus 是三个比较流行的 CSS Modules 预处理库。在 React 中,使用 CSS
Modules 的好处在于:
1. 避免全局样式冲突:使用 CSS Modules 可以确保样式只应用于特定组件,避免全局样式冲突。
2. 更好的可维护性: CSS Modules 使得样式与组件代码紧密关联,方便代码维护。
3. 提高代码可重用性: CSS Modules 可以轻松地将样式从一个组件复制到另一个组件,提高代码可
重用性。
4. 支持动态样式:使用 CSS Modules 可以轻松地生成动态样式,例如根据组件状态或属性更改样
式。
5. 更好的性能: CSS Modules 使用模块化的方式加载样式,提高了页面加载速度和性能。

基本用法

先安装相关的依赖
pnpm i less less - loader sass - loader sass stylus stylus - loader - D

webpack.base.ts 添加相关的 loader

const cssRegex = /\.css$/;
const sassRegex = /\.(scss|sass)$/;
const lessRegex = /\.less$/;
const stylRegex = /\.styl$/;
const styleLoadersArray = [
  "style-loader",
  {
    loader: "css-loader",
    options: {
      modules: {
        localIdentName: "[path][name]__[local]--[hash:5]",
      },
    },
  },
];
const baseConfig: Configuration = {
  // ...
  module: {
    rules: [
      // ...
      {
        test: cssRegex, // 匹配css文件
        use: styleLoadersArray,
      },
      {
        test: lessRegex,
        use: [
          ...styleLoadersArray,
          {
            loader: "less-loader",
            options: {
              lessOptions: {
                // 如果要在less中写js的语法,需要加这一配置
                javascriptEnabled: true,
              },
            },
          },
        ],
      },
      {
        test: sassRegex,
        use: [
          ...styleLoadersArray,
          {
            loader: "sass-loader",
            options: {
              implementation: require("sass"), // 使用dart-sass代替node-sass
            },
          },
        ],
      },
      {
        test: stylRegex,
        use: [...styleLoadersArray, "stylus-loader"],
      },
    ],
  },
  // ...
};
export default baseConfig;

 然后就可以在业务中使用了:

@color: red;
.lessBox {
  .box {
    color: @color;
    background-color: lightblue;
    transform: translateX(100);
    &:before {
      @arr: "hello", "world";
      content: ` @{arr}.join(" ") .toUpperCase() `;
    }
  }
}

$blue: #1875e7;
$side: left;
.scssBox {
    margin: 20px 0;
    .box {
        color: $blue;
        background-color: rgb(226, 223, 223);
        border: 1px solid grey;
        margin-#{$side}: 20px;
        padding: (20px/2);
  }
}
/* src/app.styl */
.stylBox
.box
color: red;
background-color: yellow;
App.tsx 中引入:
import '@/App.css'
import lessStyles from './app.less'
import scssStyles from './app.scss'
import stylStyles from './app.styl'
function App() {
return <div>
<h2>webpack5-react-ts</h2>
<div className={lessStyles['lessBox']}>
<div className={lessStyles['box']}>lessBox</div>
</div>
<div className={scssStyles['scssBox']}>
<div className={scssStyles['box']}>scssBox</div>
</div>
<div className={stylStyles['stylBox']}>
<div className={stylStyles['box']}>stylBox</div>
</div>
</div>
}
export default App
重启项目,就会发现生成了带有 hash 值的 class 类名,且里面包含了我们自定义的类名,方便日后调试 用。
同时在验证打包是否成功,运行 pnpm run build:dev ,然后通过 serve -S dist 查看。 当然,如果
你不希望每次写 less 的时候,都在文件名上加一个 .module ,可以在 less-loader 中添加如下配置:
const baseConfig: Configuration = {
module: {
rules: [
// ...
{
test: lessRegex,
use: [
...styleLoadersArray,
{
loader: "less-loader",
options: {
lessOptions: {
importLoaders: 2,
// 可以加入modules: true,这样就不需要在less文件名加module了
modules: true,
// 如果要在less中写类型js的语法,需要加这一个配置
javascriptEnabled: true
},
},
},
],
},
// ...
],
},
// ...
};
export default baseConfig;
至此,我们就完成了 less sass scss stylus 的引入
declare module '*.css' {
const classes: { [key: string]: string };
export default classes;
}
declare module '*.scss' {
const classes: { [key: string]: string };
export default classes;
}
declare module '*.sass' {
const classes: { [key: string]: string };
export default classes;
}
declare module '*.less' {
const classes: { [key: string]: string };
export default classes;
}
declare module '*.styl' {
const classes: { [key: string]: string };
export default classes;
}
然后就可以删掉样式文件中的 .module 后缀了

处理CSS3前缀在浏览器中的兼容

虽然 css3 现在浏览器支持率已经很高了 , 但有时候需要兼容一些低版本浏览器,需要给 css3 加前缀 , 可 以借助插件来自动加前缀, postcss-loader 就是来给 css3 加浏览器前缀的,安装依赖:
pnpm i postcss - loader autoprefixer - D
为了避免 webpack.base.ts 文件过于庞大,我们将一些 loader 配置提取成单独的文件来进行管理,根 目录新建 postcss.config.js ,作为 postcss-loader 的配置文件,会自动读取配置:

module.exports = {
ident: "postcss",
plugins: [require("autoprefixer")],
};
修改 webpack.base.ts ,在解析 css less 的规则中添加配置:
const styleLoadersArray = [
"style-loader",
{
loader: "css-loader",
options: {
modules: {
localIdentName: "[path][name]__[local]--[hash:5]",
},
},
},
// 添加 postcss-loader
'postcss-loader'
];
配置完成后,需要有一份要兼容浏览器的清单,让 postcss-loader 知道要加哪些浏览器的前缀,在根 目录创建 .browserslistrc 文件:
IE 9 # 兼容 IE 9
chrome 35 # 兼容 chrome 35
以兼容到 ie9 chrome35 版本为例,配置好后,在 app.module.less 中加入一些 CSS3 的语法,重新启动项目,就可以在浏览器的控制台-Elements 中看到配置成功了。
执行 pnpm run build:dev 打包,也可以看到打包后的 css 文件已经加上了 ie 和谷歌内核的前缀。

处理图片

对于图片文件, webpack4 使用 file-loader url-loader 来处理的,但 webpack5 不使用这两个
loader , 而是采用自带的 asset-module 来处理,修改 webpack.base.ts ,添加图片解析配置

{
output: {
// ... 这里自定义输出文件名的方式是,将某些资源发送到指定目录
assetModuleFilename: 'images/[hash][ext][query]'
},
module: {
rules: [
// ...
{
test: /\.(png|jpe?g|gif|svg)$/i, // 匹配图片文件
type: "asset", // type选择asset
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, // 小于10kb转base64
}
},
generator:{
filename:'static/images/[hash][ext][query]', // 文件输出目录和命名
},
},
]
}
}

 

资源模块类型
描述
asset/resource
发送一个单独的文件,并导出 URL ,替代 file-loader ,相当于 file-loader , 将文件转化成 Webpack 能识别的资源,其他不做处理。
asset/inline
导出一个资源的 data URI ,以前使用 url-loader 实现。
asset/source
导出资源的源代码 ,以前是使用 raw-loader 实现。

 

资源模块类型
描述
asset
相当于自动选择 asset/resource asset/inline ,替换 url-loader 中的 limit ,相当于 url-loader 将文件转化成 Webpack 能识别的资源, 同时小于某个大小的资源会处理成 data URI 形式。
将文件编译为 Data URI 使用,可以节省 HTTP 请求,是一个性能优化的点。但是将图片文件经
base64 编码转为 Data URI ,体积会增加大约 33% 。所以,我们一般只针对小图片做 Base64
的处理,对于一些比较大的文件来说,转为 Data URI 会明显增加打包后文件的体积,反而会加
大对带宽资源和流量的需求。
由于我们希望通过 ES6 的新语法 ESModule 的方式导入资源,为了使 TypeScript 可以识别图片模
块,需要在 src/typings/global.d.ts 中加入声明:
/* IMAGES */
declare module '*.svg' {
const ref: string;
export default ref;
}
declare module '*.bmp' {
const ref: string;
export default ref;
}
declare module '*.gif' {
const ref: string;
export default ref;
}
declare module '*.jpg' {
const ref: string;
export default ref;
}
declare module '*.jpeg' {
const ref: string;
export default ref;
}
declare module '*.png' {
const ref: string;
export default ref;
}
然后在 App.tsx 中引入图片资源:
import '@/App.css'
import lessStyles from '@/app.less'
import scssStyles from '@/app.scss'
import stylStyles from '@/app.styl'
import smallImg from '@/assets/images/5kb_img.jpeg'
import bigImg from '@/assets/images/10kb_img.png'
function App() {
return <div>
<h2>webpack5-react-ts</h2>
<div className={lessStyles['lessBox']}>
<div className={lessStyles['box']}>lessBox
<img src={smallImg} alt="小于10kb的图片" />
<img src={bigImg} alt="大于于10kb的图片" />
<div className={lessStyles['smallImg']}>小图片背景</div>
<div className={lessStyles['bigImg']}>大图片背景</div>
</div>
</div>
<div className={scssStyles['scssBox']}>
<div className={scssStyles['box']}>scssBox</div>
</div>
<div className={stylStyles['stylBox']}>
<div className={stylStyles['box']}>stylBox</div>
</div>
</div>
}
export default App
app.less 文件中加入背景图片:
@color: red;
.lessBox {
.box {
color: @color;
background-color: lightblue;
transform: translateX(100);
&:before{
@arr: 'hello', 'world';
content: `@{arr}.join(' ').toUpperCase()`;
}
}
.smallImg {
width: 69px;
height: 75px;
background: url('@/assets/imgs/5kb_img.jpeg') no-repeat;
}
.bigImg {
width: 232px;
height: 154px;
background: url('@/assets/imgs/10kb_img.png') no-repeat;
}
}
重启项目,可以看到图片被正确地展示出来了,图片被打包进了我们指定的 static/images 文件里面。

webpack构建速度优化

webpack 进度条

webpackbar 这是一款个人感觉是个十分美观优雅的进度条,很多成名框架都用过他。而且使用起来也 极其方便,也可以支持多个并发构建是个十分强大的进度插件。
pnpm i webpackbar -D

最常用的属性配置其实就是这些,注释里也写的很清楚了,我们在 webpack.base.ts 中引入:

import WebpackBar from 'webpackbar';
const baseConfig: Configuration = {
// ...
// plugins 的配置
plugins: [
// ...
new WebpackBar({
color: "#85d", // 默认green,进度条颜色支持HEX
basic: false, // 默认true,启用一个简单的日志报告器
profile:false, // 默认false,启用探查器。
})
],
};
export default baseConfig;

 

当然里面还有一个属性就是 reporters 还没有写上,可以在里面注册事件,也可以理解为各种钩子函 数。如下:
{ // 注册一个自定义数组
start(context) {
// 在(重新)编译开始时调用
const { start, progress, message, details, request, hasErrors } = context
},
change(context) {
// 在 watch 模式下文件更改时调用
},
update(context) {
// 在每次进度更新后调用
},
done(context) {
// 编译完成时调用
},
progress(context) {
// 构建进度更新时调用
},
allDone(context) {
// 当编译完成时调用
},
beforeAllDone(context) {
// 当编译完成前调用
},
afterAllDone(context) {
// 当编译完成后调用
},
}

构建耗时

当进行优化的时候,肯定要先知道时间都花费在哪些步骤上了,而 speed-measure-webpackplugin 插 件可以帮我们做到,安装依赖:
pnpm i speed-measure-webpack-plugin -D
使用的时候为了不影响到正常的开发 / 打包模式,我们选择新建一个配置文件,新增 webpack 构建分析配 置文件 build/webpack.analy.ts
import { Configuration } from 'webpack'
import prodConfig from './webpack.prod' // 引入打包配置
import { merge } from 'webpack-merge' // 引入合并webpack配置方法
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin'); // 引入webpack
打包速度分析插件
const smp = new SpeedMeasurePlugin(); // 实例化分析插件
// 使用smp.wrap方法,把生产环境配置传进去,由于后面可能会加分析配置,所以先留出合并空位
const analyConfig: Configuration = smp.wrap(merge(prodConfig, {
}))
export default analyConfig
修改 package.json 添加启动 webpack 打包分析脚本命令,在 scripts 新增:
{
// ...
"scripts": {
// ...
"build:analy": "cross-env NODE_ENV=production BASE_ENV=production webpack -c
build/webpack.analy.ts"
}
// ...
}
执行 pnpm build:analy 命令, 可以在图中看到各 plugin loader 的耗时时间 , 现在因为项目内容比较少,所以耗时都比较少,在真正 的项目中可以通过这个来分析打包时间花费在什么地方,然后来针对性的优化。

 

开启多线程 loader

webpack loader 默认在单线程执行,现代电脑一般都有多核 cpu ,可以借助多核 cpu 开启多线程 loader 解析,可以极大地提升 loader 解析的速度, thread-loader 就是用来开启多进程解析 loader
的,安装依赖
pnpm i thread-loader -D
使用时 , 需将此 loader 放置在其他 loader 之前。放置在此 loader 之后的 loader 会在一个独立的
worker 池中运行。
修改 webpack.base.ts
module: {
rules: [
{
test: /\.(ts|tsx)$/, // 匹配ts和tsx文件
use: [
// 开启多进程打包。
// 进程启动大概为600ms,进程通信也有开销。
// 只有工作消耗时间比较长,才需要多进程打包
{
loader: 'thread-loader',
options: {
wokers: 4 // 进程数
}
},
'babel-loader']
},
]
}
由于 thread-loader 不支持抽离 css 插件 MiniCssExtractPlugin.loader ( 下面会讲 ) ,所以这里只配
置了多进程解析 ts

 

webpack构建产物优化

bundle 体积分析工具

webpack-bundle-analyzer 是分析 webpack 打包后文件的插件,使用交互式可缩放树形图可视化
webpack 输出文件的大小。通过该插件可以对打包后的文件进行观察和分析,可以方便我们对不完美的 地方针对性的优化,安装依赖:
       
pnpm i webpack-bundle-analyzer -D

修改 webpack.analy.ts

import { Configuration } from "webpack";
import { merge } from "webpack-merge";
import prodConfig from "./webpack.prod";
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
// 引入webpack打包速度分析插件
const smp = new SpeedMeasurePlugin();
// 使用smp.wrap方法,把生产环境配置传进去,由于后面可能会加分析配置,所以先留出合并空位
const analyConfig: Configuration = smp.wrap(merge(prodConfig, {
plugins: [
new BundleAnalyzerPlugin() // 配置分析打包结果插件
]
}))
export default analyConfig;

 

配置好后,执行 pnpm run build:analy 命令,打包完成后浏览器会自动打开窗口,可以看到打包文件 的分析结果页面,可以看到各个文件所占的资源大小, 然后,我们就可以根据这个图上给出的信息,来针对性优化产物体积。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值