手把手带你搭建前端项目: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前端实验室 🛠️「精选资源|实战经验|技术洞见」

相关推荐
九月TTS23 分钟前
TTS-Web-Vue系列:移动端侧边栏与响应式布局深度优化
前端·javascript·vue.js
Johnstons25 分钟前
AnaTraf:深度解析网络性能分析(NPM)
前端·网络·安全·web安全·npm·网络流量监控·网络流量分析
whatever who cares1 小时前
CSS3 伪元素(Pseudo-elements)大全
前端·css·css3
若愚67921 小时前
前端取经路——性能优化:唐僧的九道心经
前端·性能优化
Bl_a_ck2 小时前
开发环境(Development Environment)
开发语言·前端·javascript·typescript·ecmascript
田本初2 小时前
使用vite重构vue-cli的vue3项目
前端·vue.js·重构
ai产品老杨2 小时前
AI赋能安全生产,推进数智化转型的智慧油站开源了。
前端·javascript·vue.js·人工智能·ecmascript
帮帮志2 小时前
vue实现与后台springboot传递数据【传值/取值 Axios 】
前端·vue.js·spring boot
xixingzhe22 小时前
Nginx 配置多个监听端口
服务器·前端·nginx
清风细雨_林木木3 小时前
Vue 2 项目中配置 Tailwind CSS 和 Font Awesome 的最佳实践
前端·css·vue.js