รักษาการควบคุม: A Guide to Webpack and React, Pt. 2

เผยแพร่แล้ว: 2022-03-11

ในส่วนแรกของบทช่วยสอน React-Webpack นี้ เราได้พูดถึงวิธีกำหนดค่าตัวโหลดและดำเนินการปรับให้เหมาะสม ตอนนี้ เราจะเข้าสู่เทคนิคขั้นสูงเพิ่มเติมที่เกี่ยวข้องกับกรณีการใช้งานการกำหนดค่า React/Webpack ที่เฉพาะเจาะจง

TypeScript และโต้ตอบกับ Webpack: ป้อน Babel

คุณสามารถใช้ TypeScript ในโครงการ React ได้หลายวิธี แม้ว่า ts-loader จะเป็นตัวเลือกที่ดี แต่ฉันต้องการเน้นที่วิธีการ transpile TypeScript โดยใช้ @babel/preset-typescript เนื่องจากห้องสมุดหลายแห่งกำลังเผยแพร่ปลั๊กอิน Babel เพื่อทำการเพิ่มประสิทธิภาพเวลาคอมไพล์ นอกเหนือจากการประมวลผลไฟล์ TypeScript แล้ว ยังช่วยให้เราใช้ปลั๊กอิน Babel ที่จัดเตรียมโดยไลบรารีต่างๆ เช่น styled-components หรือ react-intl

สิ่งแรกที่เราต้องทำคือติดตั้งการพึ่งพา TypeScript และ Babel:

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

จากนั้นเราจะสร้างไฟล์การกำหนดค่า TypeScript โดยใช้โปรแกรมบรรทัดคำสั่ง tsc :

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

คำสั่งด้านบนจะสร้าง tsconfig.json ที่เหมาะสำหรับการเขียนโค้ดสำหรับสภาพแวดล้อมของเบราว์เซอร์ ตัวเลือก --isolatedModules บังคับใช้ข้อจำกัดบางประการ ซึ่งทำให้แน่ใจว่าโค้ดที่คุณเขียนจะเข้ากันได้กับ @babel/plugin-transform-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",

และเปิดใช้งานนามสกุลไฟล์ .ts ใน webpack.config.js :

 @@ -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

จากนั้น เราจะเพิ่มลงในส่วน plugins ใน webpack.config.js :

 @@ -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 จากมุมมองของไฟล์ JavaScript ที่ใช้โมดูล CSS การเชื่อมโยงระหว่างชื่อคลาสดั้งเดิมกับชื่อคลาสแบบสุ่มจะแสดงโดยอ็อบเจ็กต์ที่ส่งออกโดยตัวโหลด ช่วยให้คุณค้นหาและใช้คลาสที่ระบุในไฟล์ 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 Modules

PostCSS

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 : ใช้ polyfills เพื่อรองรับคุณสมบัติ CSS ที่ทันสมัยในเบราว์เซอร์ส่วนใหญ่

สร้างไฟล์ชื่อ postcss.config.js และใส่ข้อมูลดังต่อไปนี้:

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

คุณสามารถตรวจสอบไดเร็กทอรีปลั๊กอิน PostCSS สำหรับส่วนขยายอื่นๆ ที่คุณอาจพบว่ามีประโยชน์และเพิ่มลงในการกำหนดค่าของคุณ

Sass/SCSS

Sass เป็นอีกหนึ่งเฟรมเวิร์กการประมวลผล CSS ยอดนิยม Sass มาพร้อมกับ "แบตเตอรี่" ซึ่งแตกต่างจาก PostCSS นอกกรอบ Sass ให้การสนับสนุนกฎที่ซ้อนกัน มิกซ์อิน และกฎการเขียนซ้ำสำหรับความเข้ากันได้แบบย้อนหลัง แม้ว่า 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. เราแนะนำ resolve-url-loader หลัง sass-loader เพื่อให้การนำเข้าแบบสัมพันธ์ทำงานได้จากไฟล์ @import ed Sass

  2. เราระบุตัวเลือก importLoaders สำหรับ css-loader เพื่อประมวลผลไฟล์ @import -ed โดยใช้ตัวโหลดที่ตามมา

ด้วยการกำหนดค่าข้างต้น เราสามารถเริ่มเขียนสไตล์ของเราโดยใช้ Sass/SCSS นอกเหนือจากโมดูล PostCSS และ CSS ที่เราได้อธิบายไว้ก่อนหน้านี้ แม้ว่าตัวเลือกเหล่านี้ทั้งหมดสามารถเปิดใช้งานพร้อมกันได้ แต่คุณไม่จำเป็นต้องใช้ทั้งหมดภายในโปรเจ็กต์เดียวกัน ดังนั้นคุณสามารถเลือกเครื่องมือเดียวที่เหมาะกับความต้องการของคุณมากที่สุด

พนักงานเว็บ

คนงานเว็บ เป็นแนวคิดที่มีประสิทธิภาพของเว็บสมัยใหม่ ช่วยให้คุณถ่ายการคำนวณที่มีราคาแพงออกจากเธรดหลักได้ ควรใช้ผู้ปฏิบัติงานเว็บเท่าที่จำเป็นและสงวนไว้สำหรับสิ่งที่ไม่สามารถเพิ่มประสิทธิภาพได้ด้วยการจัดกำหนดการอัจฉริยะภายในวนรอบเหตุการณ์ การใช้ผู้ปฏิบัติงานเว็บเป็นตัวเลือกที่ดีสำหรับการเพิ่มประสิทธิภาพการทำงานแบบซิงโครนัสที่ยาวนาน

Webpack ทำให้ง่ายต่อการใช้งานเว็บผู้ปฏิบัติงานด้วย worker-loader ซึ่งรวมไฟล์ของผู้ปฏิบัติงานไว้ในไดเร็กทอรีเอาต์พุตและจัดเตรียมคลาสผู้ปฏิบัติงานให้กับไฟล์ผู้บริโภค

ขั้นแรก เราต้องติดตั้ง 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: [

ตอนนี้ สิ่งที่คุณต้องทำเพื่อเริ่มใช้งานเว็บเวิร์กเกอร์คือสร้างอินสแตนซ์ของคลาสที่นำเข้าจากไฟล์ที่ลงท้ายด้วย . .worker.js ที่ใช้ Worker API แบบธรรมดา

พนักงานบริการ

เจ้าหน้าที่บริการเปิดใช้งานเทคนิคการเพิ่มประสิทธิภาพขั้นสูงและการปรับปรุงประสบการณ์ผู้ใช้ พวกเขาให้แอปของคุณทำงานแบบออฟไลน์เมื่อผู้ใช้ขาดการเชื่อมต่อเครือข่าย พวกเขายังให้แอปของคุณโหลดได้ทันทีแม้หลังจากกดอัปเดต

Webpack ทำให้ง่ายต่อการกำหนดค่าพนักงานบริการสำหรับแอปของคุณโดยใช้โมดูล workbox-webpack-plugin ขั้นแรกเราต้องติดตั้ง:

 npm install -D workbox-webpack-plugin

จากนั้น เราจะเพิ่มปลั๊กอินในส่วน plugins ของการกำหนดค่า Webpack ของเรา:

 @@ -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 แนะนำให้พนักงานบริการควบคุมเพจทันทีหลังจากการลงทะเบียน และเริ่มให้บริการทรัพยากรที่แคชไว้ แทนที่จะรอการโหลดหน้าถัดไป
  • skipWaiting ทำให้การอัปเดตพนักงานบริการมีผลทันที แทนที่จะรอให้อินสแตนซ์ที่ใช้งานอยู่ทั้งหมดถูกทำลาย

มีเหตุผลที่ดีว่าทำไมสองตัวเลือกหลังจึงไม่ใช่ค่าเริ่มต้น เมื่อเปิดใช้งานพร้อมกัน จะมีโอกาสเกิดข้อผิดพลาดในสถานการณ์ที่มีความอ่อนไหวด้านเวลา ดังนั้นจึงขึ้นอยู่กับคุณที่จะตัดสินใจว่าจะเปิดใช้งานตัวเลือกเหล่านั้นในการกำหนดค่าของคุณหรือไม่

สุดท้าย เราต้องลงทะเบียนพนักงานบริการเมื่อผู้ใช้เปิดแอปของเรา:

 @@ -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"); + }); +}

พนักงานบริการมีความสามารถมากกว่าการเพิ่มความสามารถแบบออฟไลน์ให้กับแอปของเรา หากคุณต้องการการควบคุมพฤติกรรมของพนักงานบริการในระดับที่สูงขึ้น คุณอาจใช้ปลั๊กอิน InjectManifest แทน ด้วยการเขียนไฟล์พนักงานบริการของคุณเอง คุณยังสามารถเปิดใช้งานการแคชสำหรับคำขอ API และใช้คุณลักษณะอื่นๆ ที่เปิดใช้งานโดยพนักงานบริการ เช่น การแจ้งเตือนแบบพุช คุณสามารถหาข้อมูลเพิ่มเติมเกี่ยวกับความสามารถของ Workbox ได้ในส่วน Advanced Recipes ของเอกสารอย่างเป็นทางการ

Advanced React Webpack Config: มอบความได้เปรียบให้กับโปรเจกต์ของคุณ

ส่วนที่สองของชุดการสอน Webpack ของเราควรให้ความรู้ที่จำเป็นแก่คุณในการขยายการกำหนดค่า Webpack ของคุณ ให้พ้นกรณีการใช้งาน React ทั่วไปส่วนใหญ่ ฉันหวังว่าคุณจะพบว่าข้อมูลนี้มีประโยชน์ และคุณสามารถขยายการกำหนดค่าส่วนบุคคลของคุณได้อย่างมั่นใจ เพื่อให้บรรลุเป้าหมายเฉพาะสำหรับโครงการของคุณ

เช่นเคย คุณสามารถค้นหาไฟล์การกำหนดค่าทั้งหมดบน GitHub และดูเอกสารประกอบของ Webpack และส่วนปลั๊กอินเพื่อค้นหาสูตรเพิ่มเติมที่เกี่ยวข้องกับเป้าหมายของคุณ ขอบคุณสำหรับการอ่าน!