保持控制:Webpack 和 React 指南,Pt。 2

已发表: 2022-03-11

在这个 React-Webpack 教程的第一部分,我们讨论了如何配置加载器和执行优化。 现在,我们将进入与特定 React/Webpack 配置用例相关的更高级技术。

TypeScript 和 React with Webpack:进入 Babel

您可以通过多种方式在 React 项目中使用 TypeScript。 虽然ts-loader是一个不错的选择,但我想专注于如何使用@babel/preset-typescript typescript 转译 TypeScript,因为许多库都在发布 Babel 插件来执行编译时优化。 除了处理 TypeScript 文件,它还允许我们使用各种库提供的 Babel 插件,例如 styled-components 或 react-intl。

我们需要做的第一件事是安装 TypeScript 和 Babel 依赖项:

 npm install -D typescript @babel/preset-typescript @types/react @types/react-dom

然后我们将使用命令行程序tsc生成一个 TypeScript 配置文件:

 ./node_modules/.bin/tsc -init --lib dom --jsx react --isolatedModules

上面的命令将生成一个适合为浏览器环境编写代码的tsconfig.json--isolatedModules选项强制执行一些约束,以确保您编写的代码与@babel/plugin-transform-typescript typescript 兼容。 此选项很有用,以便您的 IDE 在您以 Babel 无法转换的方式编写代码时向您发出警告。

接下来,我们将通过引入一个新的预设来更新babel.config.js

 @@ -6,7 +6,8 @@ module.exports = { modules: false } ], - "@babel/preset-react" + "@babel/preset-react", + "@babel/preset-typescript" ], plugins: [ "@babel/plugin-transform-runtime",

并在webpack.config.js中启用.ts文件扩展名:

 @@ -11,7 +11,7 @@ module.exports = function(_env, argv) { return { devtool: isDevelopment && "cheap-module-source-map", - entry: "./src/index.js", + entry: "./src/index.tsx", output: { path: path.resolve(__dirname, "dist"), filename: "assets/js/[name].[contenthash:8].js", @@ -20,7 +20,7 @@ module.exports = function(_env, argv) { module: { rules: [ { - test: /\.jsx?$/, + test: /\.(js|jsx|ts|tsx)$/, exclude: /node_modules/, use: { loader: "babel-loader", @@ -61,6 +61,9 @@ module.exports = function(_env, argv) { } ] }, + resolve: { + extensions: [".js", ".jsx", ".ts", ".tsx"] + }, plugins: [ isProduction && new MiniCssExtractPlugin({

上面的配置足以编译我们的代码,但实际上并没有验证它。 我们需要使用fork-ts-checker-webpack-plugin在单独的并行进程中执行类型检查。

首先,我们需要安装它:

 npm install -D fork-ts-checker-webpack-plugin

然后,我们将它添加到webpack.config.jsplugins部分:

 @@ -4,6 +4,7 @@ const HtmlWebpackPlugin = require("html-webpack-plugin"); const webpack = require("webpack"); const TerserWebpackPlugin = require("terser-webpack-plugin"); const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin"); +const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); module.exports = function(_env, argv) { const isProduction = argv.mode === "production"; @@ -78,6 +79,9 @@ module.exports = function(_env, argv) { "process.env.NODE_ENV": JSON.stringify( isProduction ? "production" : "development" ) + }), + new ForkTsCheckerWebpackPlugin({ + async: false }) ].filter(Boolean), optimization: {

指定async: false将防止 Webpack 在运行开发服务器时发出无效代码并在叠加层中显示编译错误。

注意:您可能还对 Babel 宏感兴趣,它正在获得关注。

CSS,通过 Webpack 增强

在上一篇文章中,我们介绍了使用css-loader基本样式。 我们可以通过多种方式改进此配置。

建议的配置将利用 CSS Modules、Sass 和 PostCSS 技术。 尽管它们在某些方面确实相互补充,但您不需要同时使用所有这些。 最终设置将启用所有上述插件,如果您确定“您不需要它”,我们将留给您留下一些东西。

CSS 模块

CSS 模块通过为每个 CSS 类生成一个随机的、唯一的名称来解决 CSS 文件中的全局范围问题。 从使用 CSS 模块的 JavaScript 文件的角度来看,原始类名和随机类名之间的关联由加载器导出的对象表示。 它允许您以几乎不可能发生意外碰撞的方式查找和使用 CSS 文件中指定的类。

CSS 模块支持已经包含在css-loader中。 现在我们需要添加一个新规则来明确何时使用 CSS 模块:

 @@ -33,11 +33,25 @@ module.exports = function(_env, argv) { }, { test: /\.css$/, use: [ isProduction ? MiniCssExtractPlugin.loader : "style-loader", "css-loader" ] }, + { + test: /\.module.css$/, + use: [ + isProduction ? MiniCssExtractPlugin.loader : "style-loader", + { + loader: "css-loader", + options: { + modules: true + } + } + ] + }, { test: /\.(png|jpg|gif)$/i, use: {

这样,任何以.module.css结尾的文件都将在启用 CSS 模块的情况下进行处理。

后CSS

PostCSS 是一个可扩展的 CSS 处理框架,具有庞大的插件库,您可以使用这些插件库来扩展 CSS 语法、执行优化或为旧浏览器提供回退。

首先,我们将安装必要的依赖项:

 npm install -D postcss-loader postcss-import postcss-preset-env

并更新我们的 CSS 配置:

 @@ -47,9 +47,11 @@ module.exports = function(_env, argv) { { loader: "css-loader", options: { - modules: true + modules: true, + importLoaders: 1 } - } + }, + "postcss-loader" ] }, {

我们将使用以下插件配置 PostCSS:

  • postcss-import :使 PostCSS 能够处理@import语句
  • postcss-preset-env :在大多数浏览器中应用 polyfill 来支持现代 CSS 功能

创建一个名为postcss.config.js的文件并使用以下内容填充它:

 module.exports = { plugins: { "postcss-import": {}, "postcss-preset-env": {} } };

您可以查看 PostCSS 插件目录以获取您可能觉得有用的其他扩展并将它们添加到您的配置中。

萨斯/SCSS

Sass 是另一个流行的 CSS 处理框架。 与 PostCSS 不同,Sass 带有“包括电池”。 开箱即用,Sass 提供对嵌套规则、mixin 和重写规则的支持以实现向后兼容性。 虽然 PostCSS 旨在保留标准 CSS 语法,但 Sass 语法可能与 CSS 规范有所不同。 尽管如此,Sass 是一个如此普遍的解决方案,使用它来创作 CSS 可能只是一个更简单的选择——但这取决于你的要求。

首先,我们将安装必要的依赖项:

 npm install -D sass-loader node-sass resolve-url-loader

然后,在我们的 Webpack 配置中添加一个新的加载器:

 @@ -38,6 +38,25 @@ module.exports = function(_env, argv) { "css-loader" ] }, + { + test: /\.s[ac]ss$/, + use: [ + isProduction ? MiniCssExtractPlugin.loader : "style-loader", + { + loader: "css-loader", + options: { + importLoaders: 2 + } + }, + "resolve-url-loader", + { + loader: "sass-loader", + options: { + sourceMap: true + } + } + ] + }, { test: /\.(png|jpg|gif)$/i, use: {

我们先发制人地解决了上述代码段的几个问题:

  1. 我们在sass-loader resolve-url-loader loader 以使相对导入从@import ed Sass 文件中工作。

  2. 我们为css-loader指定importLoaders选项,以使用其后面的加载器处理@import -ed 文件。

通过上述配置,我们可以开始使用 Sass/SCSS 以及我们之前描述的 PostCSS 和 CSS 模块来创作我们的样式。 尽管可以同时启用所有这些选项,但您不必在同一个项目中全部使用它们,因此您可以选择最适合您要求的一种工具。

网络工作者

网络工作者是现代网络的一个强大概念。 它使您可以从主线程中卸载昂贵的计算。 Web Worker 应该谨慎使用,并保留用于无法通过事件循环内的智能调度进行优化的事情。 使用 Web Worker 是优化长时间同步操作的理想选择。

Webpack 通过worker-loader可以轻松使用 web worker,它将 worker 文件捆绑到输出目录中,并为消费者文件提供一个 worker 类。

首先,我们需要安装worker-loader

 npm install -D worker-loader

然后将其添加到我们的配置文件中:

 @@ -31,6 +31,10 @@ module.exports = function(_env, argv) { } } }, + { + test: /\.worker\.js$/, + loader: "worker-loader" + }, { test: /\.css$/, use: [

现在,开始使用 Web Worker 所需要做的就是实例化一个从以.worker.js结尾的文件导入的类,该文件实现了普通的 Worker API。

服务人员

Service Worker 支持高级优化技术并改善用户体验。 当用户失去网络连接时,它们可以让您的应用离线工作。 即使在推送更新后,它们也可以让您的应用程序立即加载。

Webpack 使用 workbox-webpack-plugin 模块可以轻松地为您的应用程序配置服务工作者。 首先,我们需要安装它:

 npm install -D workbox-webpack-plugin

然后,我们将插件添加到 Webpack 配置的plugins部分:

 @@ -4,6 +4,7 @@ const HtmlWebpackPlugin = require("html-webpack-plugin"); const webpack = require("webpack"); const TerserWebpackPlugin = require("terser-webpack-plugin"); const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin"); +const WorkboxPlugin = require("workbox-webpack-plugin"); module.exports = function(_env, argv) { const isProduction = argv.mode === "production"; @@ -75,6 +76,11 @@ module.exports = function(_env, argv) { "process.env.NODE_ENV": JSON.stringify( isProduction ? "production" : "development" ) + }), + new WorkboxPlugin.GenerateSW({ + swDest: "service-worker.js", + clientsClaim: true, + skipWaiting: true }) ].filter(Boolean), optimization: {

上述配置使用以下选项:

  • swDest指定生成的工作文件的输出文件名。
  • clientsClaim指示 service worker 在注册后立即控制页面并开始提供缓存资源,而不是等待下一个页面重新加载。
  • skipWaiting使对 service worker 的更新立即生效,而不是等待所有活动实例被销毁。

后两个选项不是默认选项是有充分理由的。 同时启用时,在时间敏感的情况下可能会发生故障,因此您需要有意识地决定是否在配置中启用这些选项。

最后,我们需要在用户打开我们的应用程序时注册 service worker:

 @@ -2,3 +2,9 @@ import React from "react"; import ReactDOM from "react-dom"; ReactDOM.render(<h3>React App</h3>, document.getElementById("root")); + +if ("serviceWorker" in navigator) { + window.addEventListener("load", () => { + navigator.serviceWorker.register("/service-worker.js"); + }); +}

服务工作者的能力远不止为我们的应用程序添加离线功能。 如果您需要对 service worker 行为进行更大程度的控制,那么您可以使用InjectManifest插件。 通过编写自己的服务工作者文件,您还可以为 API 请求启用缓存并使用服务工作者启用的其他功能,例如推送通知。 您可以在其官方文档的 Advanced Recipes 部分找到有关 Workbox 功能的更多信息。

高级 React Webpack 配置:为您的项目提供优势

我们的 Webpack 教程系列的第二部分应该为您提供必要的知识,以将您的 Webpack 配置扩展到最常见的 React 用例之外。 我希望您发现这些信息很有用,并且您可以自信地扩展您的个性化配置以实现特定于您的项目的目标。

与往常一样,您可以在 GitHub 上找到完整的配置文件,并参考 Webpack 文档及其插件部分以找到更多适用于您的目标的方法。 感谢您的阅读!