手把手带你搭建前端项目:react18、ts5、lint四剑客、webpack、storybook【保姆级教程二】

🧑‍💻 写在开头


上一篇文章手把手带你搭建前端项目:react18、ts5、lint四剑客、webpack、storybook【保姆级教程一】中我们配置了项目初始化文件,代码风格统一、代码质量检测、代码自动修复,ts基本配置等等。本篇文章我们继续完成上一篇文章未完成的工作,配置webpack打包,打包文件根据环境配置,开发服务器配置,css、less、sass、图片、字体、文件的打包。

你能学到什么?

希望在你阅读本篇文章之后,不会觉得浪费了时间。如果你跟着读下来,你将会学到:

  • 🧑‍ 配置一下生成更新日志changelog
  • 🍺 配置webpack5基本打包流程
  • 🍑 webpack5打包样式文件
  • 🍒 webpack5打包图片,字体,等文件
  • 🍎 使用rollup打包组件库代码

预告

后续我们将配置

  • 支持react和tsx,实现基本的react+ts开发环境。
  • 实现加入storybook编写组件
  • 实现rollup打包组件库,本地测试组件库,发布组件库

🍎 系列文章

配置更新日志changelog

sql 复制代码
yarn add [email protected] -D

在 package.json 的 scripts 下增加一个命令:

json 复制代码
{
  "scripts": {
    "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
  },
}

之后就可以通过 npm run changelog 生成 angular 风格的 changelog ,需要注意的是,上面这条命令产生的 changelog 是基于上次 tag 版本之后的变更(feat、fix 等等)所产生的。

Webpack5 基本配置

这个图可以大致总结webpack的配置分类和逻辑,webpack的配置其实就是这么一个流程,在打包流程的基础上在优化开发体验和产物优化的配置

安装、配置

sql 复制代码
yarn add [email protected] [email protected] -D
  • webpack :这不必多说,其用于编译 JavaScript 模块。
  • webpack-cli :此工具用于在命令行中运行 webpack。 紧接着我们在根目录下新建文件夹 scripts ,在之下再建一个文件夹 config ,在 config 中再建一个 .js 文件 webpack.common.js ,此结构如下:
arduino 复制代码
scripts/
    config/
      webpack.common.js

后面会用到webpack-merge,提取公共的逻辑,区分开发环境和生产环境的配置。

打包出、入口input、output

这里就是配置webpack打包的输入输出。

在 Webpack 5 中,配置文件(通常是 webpack.config.js)的输入(entry)和输出(output)是最基本的部分,用于定义 Webpack 应当处理的文件以及它们处理完毕应当输出到哪里。

输入(entry)

Webpack 的 Entry 配置项用于定义项目的入口点。Webpack 会从这些入口点开始,解析出项目内的依赖关系。

基础的单个入口简写语法:

ini 复制代码
module.exports = {
  entry: './path/to/my/entry/file.js'
};

对象语法,当你需要更复杂的配置时使用:

css 复制代码
module.exports = {
  entry: {
    main: './src/index.js',
    app: './src/app.js'
    // 可以添加更多入口
  }
};

常见的配置选项值:

  • 字符串:单一入口点简化写法。
  • 数组:当你想对多个文件一起打包但只创建一个 bundle。
  • 对象:多个入口点,可以创建多个 bundle。适合多页面应用。

输出(output)

配置输出属性(output)告诉 Webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值是 ./dist。 基础配置:

lua 复制代码
const path = require('path');

module.exports = {
  //...
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  }
};

多个入口起点时配置: 如果配置创建了多个单独的 "chunk"(例如,使用多个入口点或使用像 CommonsChunkPlugin 这样的插件),应该使用占位符(substitutions)来确保每个文件具有唯一的名称。

lua 复制代码
module.exports = {
  //...
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].bundle.js'
  }
};

常见的配置选项值:

  • path:输出文件所在的目录绝对路径。
  • filename:指定输出文件的名称。
  • publicPath:指定在浏览器中被引用的时候的公共的URL的路径。
  • library:暴露库的名称。作为全局变量,当你的库加载完成后,入口起点的返回值将分配给这个变量。
  • libraryTarget:在何种形式下导出库。
  • chunkFilename:非入口(non-entry) chunk 文件的名称。
  • assetModuleFilename:生成的资产(asset)文件名模版。 示例配置:
lua 复制代码
module.exports = {
  //...
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
    publicPath: '/',
    library: 'MyLibrary',
    libraryTarget: 'umd',
    chunkFilename: '[id].[chunkhash].js',
    assetModuleFilename: 'images/[hash][ext][query]'
  }
};

我们在webpack.common.js文件中配置如下,

lua 复制代码
const path = require('path')

module.exports = {
  entry: {
    app: path.resolve(__dirname, '../../src/app.js'),
  },
  output: {
    filename: 'js/[name].[hash:8].js',
    path: path.resolve(__dirname, '../../dist'),
  },
}

接下来在根目录创建 src 文件夹,新建 app.js 文件,输入以下代码:

ini 复制代码
const root = document.querySelector('#root')
root.innerHTML = 'hello, webpack!'

现在我们尝试使用刚才的 webpack 配置对其进行打包,那如何操作呢? 打开 package.json ,为其添加一条 npm 命令:

json 复制代码
{
  "scripts": {
    "build": "webpack --config ./scripts/config/webpack.common.js",
  },
}

测试,在dist下就生成了打包的文件

这里有一个警告,这里是因为我们没有配置打包环境,后面我们配置了之后就不会有了

这里解释下output.filename的配置方式和原因,

在 Webpack 中,output.filename 属性是用来定义输出文件的名称的。你可以使用静态名称的字符串,但更常用的是利用占位符来动态地为每个输出文件指定名称。以下是可用的几种配置方式,和几种不同的哈希值类型:

Filename 配置方式: 静态名称:

vbnet 复制代码
filename: 'bundle.js'

这将会输出一个名为 bundle.js 的文件。

使用入口点名称:

vbnet 复制代码
filename: '[name].js'

这里的 [name] 是一个占位符,为每个入口点生成带有其名称的输出文件。

使用内部 chunk id:

vbnet 复制代码
filename: '[id].js'

id\] 将会被替换为每个 chunk 的内部唯一标识符。 **根据内容生成的哈希值:** ```vbnet filename: '[contenthash].js' ``` \[contenthash\] 是文件内容的哈希值,一般用于缓存逻辑。 聚焦在哈希占位符,Webpack 提供了几种不同类型的哈希值,它们有不同的意图和使用场景: **Hash 值类型:** * `[hash]`:与整个项目的构建相关的哈希值。不论哪个文件有变化,整个项目构建的哈希值都会改变。 * `[chunkhash]`:与 Webpack 打包过程中生成的 chunk 相关的哈希值。同一 chunk 内文件没有变化时,\[chunkhash\] 是不变的。它可以用来优化浏览器缓存,因为不同的文件通常被打包进不同的 chunk。 * `[contenthash]`:与文件内容直接相关的哈希值。只有文件内容改变了,`[contenthash]` 才会改变。这在使用如 css-extract-plugin 分离 CSS 文件时非常有用,因为你可能只希望在 CSS 文件的内容实际发生变化时才改变文件名。 * `[modulehash]`:与单个模块相关的哈希值。 * `[fullhash]`:Webpack 5 引入的哈希值,用来代替旧版本中的 \[hash\]。 **Hash 值的区别:** * `[hash]` 和 `[fullhash]` 考虑的是整个编译过程。任何一个文件的改动都会导致所有输出文件的哈希值变化。这意味着即使只有一个文件被修改,缓存的所有文件也因为文件名改变而需要重新获取。 * `[chunkhash]` 是针对每个 chunk 的。如果不同的入口导致了不同的 chunk 输出,那么只有当特定 chunk 中的模块变化时,该 chunk 的文件名才会改变。这允许客户端缓存未变更的 chunks。 * `[contenthash]` 特别适用于 CSS 或其他静态资源离散文件的缓存策略。文件内容改变时,相关文件哈希值变化,未改变的文件则哈希值保持不变,使缓存更有效。 在使用哈希占位符时,可以指定哈希值的长度,如 `[hash:8]`,这将输出8个字符长度的哈希值,让文件名更为精简。 ## 提取公共变量 在 scripts 下新建一个 constant.js 文件,存放一些用到的常量,项目根目录的绝对路径,开发服务器的端口路径,项目名称等等。 ```arduino scripts/ config/ webpack.common.js + constant.js ``` 在里面定义我们的变量: ```ini const path = require('path') // 拼接绝对路径 const PROJECT_PATH = path.resolve(__dirname, '../') // 项目名 const PROJECT_NAME = path.parse(PROJECT_PATH).name module.exports = { PROJECT_PATH, PROJECT_NAME } ``` 然后在 webpack.common.js 中引入,修改代码: ```js const {resolve} = require('path'); const {PROJECT_PATH} = require('../constants'); module.exports = { entry: { app: resolve(PROJECT_PATH, './src/app.js'), }, output: { filename: 'js/[name].[hash:8].js', path: resolve(PROJECT_PATH, './dist'), }, }; ``` ## 区分开发/生产环境 开发环境不需要压缩代码,不需要提取css为单文件,但是需要开发服务器等优化开发体验的配置,但是生产环境又不需要,有的又是两个环境都需要的,所以我们需要区分开发、生产环境,我们可以使用[webpack-merge](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fsurvivejs%2Fwebpack-merge "https://github.com/survivejs/webpack-merge")来配置,然后合并。 ```sql yarn add [email protected] -D ``` 在 scripts/config 下新建文件 webpack.dev.js 作为开发环境配置,并输入以下代码: ```js const { merge } = require('webpack-merge') const common = require('./webpack.common.js') module.exports = merge(common, { mode: 'development', }) ``` 同样地,在 scripts/config 下新建文件 webpack.prod.js 作为生产环境配置,并输入以下代码: ```javascript const { merge } = require('webpack-merge') const common = require('./webpack.common.js') module.exports = merge(common, { mode: 'production', }) ``` 对于mode我们可以使用环境变量去区分,就可以提取到common的配置中 ## cross-env可跨平台设置和使用环境变量 cross-env 可跨平台设置和使用环境变量,不同操作系统设置环境变量的方式不一定相同,比如 Mac 电脑上使用 export NODE_ENV=development ,而 Windows 电脑上使用的是 set NODE_ENV=development ,有了这个利器,我们无需在考虑操作系统带来的差异性。 ```sql yarn add [email protected] -D ``` 然后在 package.json 中添加修改以下代码: ```json { "scripts": { "start": "cross-env NODE_ENV=development webpack --config ./scripts/config/webpack.dev.js", "build": "cross-env NODE_ENV=production webpack --config ./scripts/config/webpack.prod.js", }, } ``` 修改 srcipt/constants.js 文件,增加一个公用布尔变量 isDev : ```js const path = require('path'); const PROJECT_PATH = path.resolve(__dirname, '../'); const PROJECT_NAME = path.parse(PROJECT_PATH).name; const isDev = process.env.NODE_ENV !== 'production'; module.exports = { PROJECT_PATH, PROJECT_NAME, isDev, }; ``` hash 值在开发环境中并不需要,于是我们修改 webpack.common.js 文件: ```js const {resolve} = require('path'); const {PROJECT_PATH, isDev} = require('../constants'); module.exports = { mode: isDev ? 'development' : 'production', entry: { app: resolve(PROJECT_PATH, './src/app.js'), }, output: { filename: `js/[name]${isDev ? '' : '.[hash:8]'}.js`, path: resolve(PROJECT_PATH, './dist'), }, }; ``` ## 本地服务实时查看页面 ```sql yarn add [email protected] [email protected] -D ``` 简单介绍一下两个工具的作用: * html-webpack-plugin :每一个页面是一定要有 html 文件的,而这个插件能帮助我们将打包后的 js 文件自动引进 html 文件中,毕竟你不可能每次更改代码后都手动去引入 js 文件。 * webpack-dev-server :可以在本地起一个 http 服务,通过简单的配置还可指定其端口、热更新的开启等。 现在,我们先在项目根目录下新建一个 public 文件夹,里面存放一些公用的静态资源,现在我们先在其中新建一个 index.html ,写入以下内容: ```html React18 + Ts5 + webpack5 开发模板搭建

``` 因为 html-webpack-plugin 在开发和生产环境我们都需要配置,于是我们打开 webpck.common.js 增加以下内容: ```js const {resolve} = require('path'); const {PROJECT_PATH, isDev} = require('../constants'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const PLUGINS = [ // 配置html,自动引入打包出的js文件 new HtmlWebpackPlugin({ template: resolve(PROJECT_PATH, './public/index.html'), filename: 'index.html', cache: false, minify: isDev ? false : { removeAttributeQuotes: true, collapseWhitespace: true, removeComments: true, collapseBooleanAttributes: true, collapseInlineTagWhitespace: true, removeRedundantAttributes: true, removeScriptTypeAttributes: true, removeStyleLinkTypeAttributes: true, minifyCSS: true, minifyJS: true, minifyURLs: true, useShortDoctype: true, }, }), ]; module.exports = { mode: isDev ? 'development' : 'production', entry: { app: resolve(PROJECT_PATH, './src/app.js'), }, output: { filename: `js/[name]${isDev ? '' : '.[hash:8]'}.js`, path: resolve(PROJECT_PATH, './dist'), }, plugins: PLUGINS, }; ``` 随后在 webpack.dev.js 下增加本地服务的配置: ```js const { merge } = require("webpack-merge"); const common = require("./webpack.common.js"); const { SERVER_HOST, SERVER_PORT } = require("../constants"); module.exports = merge(common, { mode: "development", stats: "errors-only", // 终端仅打印 error devtool: "eval-source-map", devServer: { host: SERVER_HOST, // 指定 host,不设置的话默认是 localhost port: SERVER_PORT, // 指定端口,默认是8080 client: { // 控制日志输出格式 logging: "info", // 选择 'none', 'error', 'warn', 'info', 'log', 或 'verbose' }, compress: true, // 是否启用 gzip 压缩 open: true, // 打开默认浏览器 hot: true, // 热更新 }, }); ``` 我们定义了两个新的变量 SERVER_HOST 和 SERVER_PORT ,在 constants.js 中定义它们: ```js const path = require('path'); const PROJECT_PATH = path.resolve(__dirname, '../'); const PROJECT_NAME = path.parse(PROJECT_PATH).name; const isDev = process.env.NODE_ENV !== 'production'; const SERVER_HOST = '127.0.0.1'; const SERVER_PORT = 9000; module.exports = { SERVER_HOST, SERVER_PORT, PROJECT_PATH, PROJECT_NAME, isDev, }; ``` 现在配置好了本地服务的相关配置,我们还需要回到 package.json 中修改 start 命令: ```json { "scripts": { "start": "cross-env NODE_ENV=development webpack-dev-server --config ./scripts/config/webpack.dev.js", }, } ``` yarn run start测试一下,如下图 ![](https://file.jishuzhan.net/article/1776525501158920193/4e04edff8d3915f06edcdfb29ebed457.webp) ## devtool \& sourcemap devtool 是一个在 Webpack 配置中用于控制是否生成,以及如何生成 Source Map 的配置选项。Source Map 是一种用于将编译、打包、转换后的代码映射回原始源代码的工具,它在调试中非常有用,因为它允许你看到源代码级别的错误和日志信息,即使你正在运行的是转换后的代码。 Source Map: Source Map 基本上是一个文件,它提供了从原始源代码到压缩、转换代码之间的映射。这样,当你在浏览器中调试时,即便是在查看转换后的代码(例如,压缩过后的或者由 TypeScript 转换成 JavaScript 的代码),调试器也能够展示出原始源码的位置,从而使得调试过程更加直观和容易。 在 Webpack 中,有多种方式可以生成 Source Map,devtool 配置项可以接受以下值之一: * eval:每个模块会用 eval() 执行,并且在末尾追加一个 //@ sourceMappingURL 注释,最快。 * cheap-eval-source-map:生成较快,并且可以映射到行号。 * cheap-module-eval-source-map:生成较快,并且会生成 Source Map 到模块级别。 * eval-source-map:转换(transpile)每个模块,并在一个 DataUrl 中提供 Source Map,提供质量更好但速度较慢的 Source Map。 * cheap-source-map:不包含列信息的 Source Map,不包括 loader 的 Source Map。 * cheap-module-source-map:不包含列信息,但是加载器(loader)的 Source Map 会被简化为每行一个映射(mapping)。 * inline-source-map:生成一个完整的 Source Map,并以 DataUrl 的形式追加到输出文件末尾。 * source-map:生成一个独立的 Source Map 文件,提供完整的映射信息,通常用于生产环境中。 * hidden-source-map:创建 Source Map,但不在打包文件中引用,错误信息不会显示原始代码的位置信息,只会显示构建后代码的位置信息。 * nosources-source-map:创建 Source Map,但不包含 sourcesContent(原始代码内容)。 这些选项提供了不同层次的 Source Map 质量和构建性能之间的权衡。例如,在开发环境中,你可能会选择一个构建速度快的 Source Map 选项,比如 eval-source-map,以提高构建和重构建的速度。在生产环境中,为了获取好的源映射,通常会采用 source-map 或 hidden-source-map 这种完整但较慢的选项。 在 webpack.dev.js 中添加以下代码: ```js module.exports = merge(common, { mode: 'development', devtool: 'eval-source-map', }) ``` 在生产环境中我直接设为 false ,不需要 source-map 功能,在 webpack.prod.js 中添加以下代码: ```java module.exports = merge(common, { mode: 'production', devtool: false, }) ``` 通过上面配置,我们本地进行开发时,代码出现了错误,控制台的错误日志就会精确地告诉你错误的代码文件、位置等信息。比如我们在 src/app.js 中第 5 行故意写个错误代码: ```ini const root = document.querySelector('#root'); root.innerHTML = 'React18 + Ts5 + webpack5 开发模板搭建'; const a = '212132321321'; a = 21321321321; ``` 效果如下 ![](https://file.jishuzhan.net/article/1776525501158920193/cc67ff0f75fdc2ba220eb725ff9bf21b.webp) ## 打包编译前清理 dist 目录 如果不清理,dist下面的打包输出会一直累积,但是只有在生产环境下,因为我们开发环境不需要哈希值,所以每次都是app.js会直接替换文件内容 ![](https://file.jishuzhan.net/article/1776525501158920193/3ce9dbe7ca39fa8795290d195b3d9095.webp) 借助 clean-webpack-plugin 可以实现每次打包前先处理掉之前的 dist 目录,以保证每次打出的都是当前最新的,我们先安装它: ```sql yarn add [email protected] -D ``` 打开 webpack.prod.js 文件,增加以下代码: ```js const {merge} = require('webpack-merge'); const common = require('./webpack.common.js'); const {CleanWebpackPlugin} = require('clean-webpack-plugin'); const PLUGINS = [new CleanWebpackPlugin()]; module.exports = merge(common, { plugins: PLUGINS, }); ``` 效果如下 ![](https://file.jishuzhan.net/article/1776525501158920193/d4b0ae25aeabb0d212b8a74ac14cf376.webp) ## 样式文件处理 ### 处理 .css 文件 在 src/ 目录下新建一个 `app.css` 文件,给 #root 随便添加一个样式, app.js 中通过 `import './app.css'` ,再进行打包或本地服务启动,webpack 直接就会报错,报错告诉我们,我们可能需要一个其他loader去支持这种文件,因为 webpack 只会编译 .js 文件,它是不支持直接处理 .css 、 .less 或 .scss 文件的。 ![](https://file.jishuzhan.net/article/1776525501158920193/9728024ba29f1e3e212729515e393c6a.webp) 我们需要安装 style-loader 和 css-loader : ```sql yarn add [email protected] [email protected] -D ``` 遇到后缀为 .css 的文件,webpack 先用 css-loader 加载器去解析这个文件,遇到 @import 等语句就将相应样式文件引入(所以如果没有 css-loader ,就没法解析这类语句),计算后生成css字符串,接下来 style-loader 处理此字符串生成一个内容为最终解析完的 css 代码的 style 标签,放到 head 标签里。 loader 是有顺序的,webpack 肯定是先将所有 css 模块依赖解析完得到计算结果再创建 style 标签。因此应该把 style-loader 放在 css-loader 的前面(webpack loader 的执行顺序是从右到左,即从后往前)。 于是,打开我们的 webpack.common.js ,写入以下代码: ```js module.exports = { // other... module: { rules: [ { test: /\.css$/, use: [ 'style-loader', { loader: 'css-loader', options: { modules: false, // 默认就是 false, 若要开启,可在官网具体查看可配置项 sourceMap: isDev, // 开启后与 devtool 设置一致, 开发环境开启,生产环境关闭 importLoaders: 0, // 指定在 CSS loader 处理前使用的 laoder 数量 }, }, ], }, ] }, } ``` test 字段是匹配规则,针对符合规则的文件进行处理。 use 字段有几种写法: * 可以是一个字符串,假如我们只使用 style-loader ,只需要 use: 'style-loader' 。 * 可以是一个数组,假如我们不对 css-loader 做额外配置,只需要 use: \['style-loader', 'css-loader'\] 。 * 数组的每一项既可以是字符串也可以是一个对象,当我们需要在webpack 的配置文件中对 loader 进行配置,就需要将其编写为一个对象,并且在此对象的 options 字段中进行配置。比如我们上面要对 css-loader 做配置的写法。 效果如下 ![](https://file.jishuzhan.net/article/1776525501158920193/abaeae90f26a26d3d42a37bfb9580feb.webp) ### LESS文件的处理 我们先把app.css改为app.less,import也改为引入less文件,这时候会报跟css一样的错,处理 .less 文件我们需要安装 less 和 less-loader : ```sql yarn add [email protected] [email protected] -D ``` 遇到后缀为 .less 文件, * less-loader 会将你写的 less 语法转换为 css 语法,并转为 .css 文件。 * less-loader 依赖于 less ,所以必须都安装。 继续在 webpack.common.js 中写入代码: ```js module.exports = { // other... module: { rules: [ { /* ... */ }, { test: /\.less$/, use: [ 'style-loader', { loader: 'css-loader', options: { modules: false, sourceMap: isDev, importLoaders: 1, // 需要先被 less-loader 处理,所以这里设置为 1 }, }, { loader: 'less-loader', options: { sourceMap: isDev, }, }, ], }, ] }, } ``` ### SASS 样式文件处理 更改app.less为app.scss, import也更改为scss文件,处理 .scss 文件我们需要安装 node-sass 和 sass-loader : ```sql yarn add [email protected] [email protected] -D ``` 遇到 .scss 后缀的文件, sass-loader 会将你写的 sass 语法转为 css 语法,并转为 .css 文件。 同样地, sass-loader 依赖于 node-sass ,所以两个都需要安装。( node-sass 如果没有配置yarnrc文件的话可能需要挂代理, 我这里是配置了淘宝源) 继续在 webpack.common.js 中写入代码: ```js module.exports = { // other... module: { rules: [ { /* ... */ }, { test: /\.scss$/, use: [ 'style-loader', { loader: 'css-loader', options: { modules: false, sourceMap: isDev, importLoaders: 1, // 需要先被 sass-loader 处理,所以这里设置为 1 }, }, { loader: 'sass-loader', options: { sourceMap: isDev, }, }, ], }, ] }, } ``` 执行 `yarn run start` ,样式就已经正常加载了。 ### PostCSS 处理浏览器兼容问题 postcss 一种对 css 编译的工具,类似 babel 对 js 一样通过各种插件对 css 进行处理,在这里我们主要使用以下插件: * postcss-flexbugs-fixes :用于修复一些和 flex 布局相关的 bug。 * postcss-preset-env :将最新的 CSS 语法转换为目标环境的浏览器能够理解的 CSS 语法,目的是使开发者不用考虑浏览器兼容问题。我们使用 autoprefixer 来自动添加浏览器头。 * postcss-normalize :从 browserslist 中自动导入所需要的 normalize.css 内容。 安装上面提到的所需的包: ```sql yarn add [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] -D ``` 根目录增加postcss.config.js文件,新增如下配置 ```js const {isDev} = require('./scripts/constants'); module.exports = { ident: 'postcss', plugins: [ // 修复一些和 flex 布局相关的 bug require('postcss-flexbugs-fixes'), require('postcss-preset-env')({ autoprefixer: { grid: true, flexbox: 'no-2009', }, stage: 3, }), require('postcss-normalize'), ], sourceMap: isDev, }; ``` 更改webpack.common.js,这里我们提取重复的逻辑 ```js const getCssLoaders = (importLoaders) => [ 'style-loader', { loader: 'css-loader', options: { modules: false, sourceMap: isDev, importLoaders, }, }, 'postcss-loader', ]; module.exports = { mode: isDev ? 'development' : 'production', entry: { app: resolve(PROJECT_PATH, './src/app.js'), }, output: { filename: `js/[name]${isDev ? '' : '.[hash:8]'}.js`, path: resolve(PROJECT_PATH, './dist'), }, plugins: PLUGINS, module: { rules: [ { test: /\.css$/, use: getCssLoaders(1), }, { test: /\.less$/, use: [ ...getCssLoaders(2), { loader: 'less-loader', options: { sourceMap: isDev, }, }, ], }, { test: /\.scss$/, use: [ ...getCssLoaders(2), { loader: 'sass-loader', options: { sourceMap: isDev, }, }, ], }, ], }, }; ``` 在 package.json 中添加 browserslist (指定了项目的目标浏览器的范围) ```json { "browserslist": [ ">0.2%", "not dead", "ie >= 9", "not op_mini all" ], } ``` 现在,在如果你在入口文件(比如我之前一直用的 app.js )随便引一个写了 display: flex 语法的样式文件, `yarn run start` 浏览器就自动加上了前缀 ![](https://file.jishuzhan.net/article/1776525501158920193/ef53a0e12a2ad56b8e5ac884c4215791.webp) ## 处理图片和文件 我们先准备一张图片,在app.js中用import引入 ![](https://file.jishuzhan.net/article/1776525501158920193/597ff8bf3db3ece820c3883a33fdeee9.webp) ![](https://file.jishuzhan.net/article/1776525501158920193/f5234fc0f5c626c3f9debe34075f6392.webp) 这时候会报错,我们需要loader去处理图片文件,我们增加如下配置 ```js // 处理图片、文件、字体 { test: /\.(png|svg|jpg|jpeg|gif)$/i, type: "asset/resource", }, { test: /\.(woff|woff2|eot|ttf|otf)$/i, type: "asset/resource", }, { test: /\.txt/, type: "asset/source", }, { // 通用文件则使用 asset,此时会按照默认条件自动决定是否转换为 Data URI test: /\.(?:ico|gif|png|jpg|jpeg)$/i, type: "asset", parser: { // 如果文件大小小于 8kb,那么会转换为 data URI,否则为单独文件。 // 8kb 是默认值,你可以根据需要进行调整 dataUrlCondition: { maxSize: 8 * 1024, // 8kb }, }, }, ``` 在Webpack 5中处理图片、文件、字体等资源类型非常简单,因为Webpack 5内置了资源模块(Asset Modules),这是一类模块类型,它允许使用资源文件(字体、图标等)而无需配置额外的loader。 资源模块提供了四种类型: * asset/resource: 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现。 * asset/inline: 导出一个资源的 data URI。之前通过使用 url-loader 实现。 * asset/source: 导出资源的源代码。之前通过使用 raw-loader 实现。 * asset: 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader 并且配置资源体积限制实现。 针对不同类型的资源,你可以按以下方式添加规则到Webpack配置 以上是Webpack 5处理静态资源的基本配置,理解和使用资源模块可以使得资源处理更简单有效。这些配置项取代了之前在Webpack 4及以前需要使用的file-loader、url-loader和raw-loader。使用资源模块,配置变得更简洁明了,减少了构建配置的复杂性。在大多数情况下,默认的配置已经可以满足日常开发的需要。 # 🍋 写在最后 如果你看到这里了,并且觉得这篇文章对您有所帮助,希望你能够点赞👍和收藏⭐支持一下作者🙇🙇🙇,感谢🍺🍺!如果文中有任何不准确之处,也欢迎您指正,共同进步。感谢您的阅读,期待您的点赞👍和收藏⭐! 参考文章 * [我是这样搭建Typescript+React项目环境的!](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fvortesnail%2Fblog%2Fissues%2F14 "https://github.com/vortesnail/blog/issues/14") 本文主要流程参考这篇文章,将文章中的包换成了相对较新的,解决了配置过程中存在的问题,增加了一些没有的配置 感兴趣的同学可以关注下我的公众号ObjectX前端实验室 !\[\]([files.mdnice.com/user/62323/...](https://link.juejin.cn?target=https%3A%2F%2Ffiles.mdnice.com%2Fuser%2F62323%2Ff700dfe9-e2b9-4697-abc3-79ebb2df6fac.png "https://files.mdnice.com/user/62323/f700dfe9-e2b9-4697-abc3-79ebb2df6fac.png") =50%x) 🌟 少走弯路 \| ObjectX前端实验室 🛠️「精选资源|实战经验|技术洞见」

相关推荐
腾讯TNTWeb前端团队6 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰9 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy10 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom11 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom11 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom11 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom11 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom11 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试