保持控制: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.js
的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 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: {
我們先發製人地解決了上述代碼段的幾個問題:
我們在
sass-loader
resolve-url-loader
loader 以使相對導入從@import
ed Sass 文件中工作。我們為
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 文檔及其插件部分以找到更多適用於您的目標的方法。 感謝您的閱讀!