Skip to content

Instantly share code, notes, and snippets.

@relyky
Created November 19, 2024 07:37
Show Gist options
  • Save relyky/aa465eea1f9071f29b95b90af918bd44 to your computer and use it in GitHub Desktop.
Save relyky/aa465eea1f9071f29b95b90af918bd44 to your computer and use it in GitHub Desktop.
webpack.config.js 應用留存
// 與 webpack.config.lazy.js 搭配,以進行動態拆分。
import React, { lazy, Suspense, LazyExoticComponent, useMemo } from "react"
type ComponentType = LazyExoticComponent<React.ComponentType<any>>;
//## 所有作業都需先“註冊”
const funcPool = new Map<string, ComponentType>();
funcPool.set("HomeIndex", lazy(() => import(/* webpackChunkName: "HomeIndex" */'./Home/HomeIndex')));
funcPool.set("DEMO001", lazy(() => import(/* webpackChunkName: "DEMO001" */'./Demo/DEMO001/AppForm')));
funcPool.set("DEMO002", lazy(() => import(/* webpackChunkName: "DEMO002" */'./Demo/DEMO002/AppForm')));
//※ 上面的 webpackChunkName 註解資訊將在 bundle 時送至 webpack.config.js 對應的 chunk 參數 [name] 以用於 chunk.bundle.js 取名。
export default function AppMain(props: {
funcId: string
}) {
//## 依參數 funcId 取得 AppCtx
const AppCtx = useMemo(() => funcPool.get(props.funcId) ?? funcPool.get('HomeIndex')
, [funcPool, props.funcId])
console.log('App.AppForm.v1', { props })
return (
<div>
<h1>AppForm</h1>
<a href="/">Home</a>&nbsp;&nbsp;
<a href="/Demo/DEMO001">DEMO001</a>&nbsp;&nbsp;
<a href="/Demo/DEMO002">DEMO002</a>&nbsp;&nbsp;
<main>
<Suspense fallback={<Spinner />}>
<AppCtx />
</Suspense>
</main>
</div>
)
}
const Spinner: React.FC = () => (
<div className="text-center bg-light text-primary p-4 ">
<i className="fa fa-cog fa-spin fa-5x"></i>
<p>載入中</p>
</div>
)
/*
* 單進入點與動態 lazy 載入。
* 應用於 "webpack": "^5.88.2", "webpack-cli": "^5.1.4", "react": "^18.3.1", "react-dom": "^18.3.1",
* 需挑配 React lazy 指令進行動態拆分。
*/
//const HtmlWebPackPlugin = require("html-webpack-plugin");
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = [{
context: __dirname,
entry: {
app: './src/app.tsx',
},
output: {
path: path.resolve(__dirname, '../N48MvcReactLab/Scripts/bundle/'),
filename: '[name].bundle.js',
publicPath: '/Scripts/bundle/',
chunkFilename: '[name].bundle.js'
},
module: {
rules: [
{
test: /\.?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
use: [
"style-loader",
"css-loader",
],
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
alias: {
hooks: path.resolve(__dirname, 'src/hooks/'),
}
},
optimization: {
// minimize: true, // 預設當執行[webpack --mode production]模式指令時會觸發[minimizer]動作。
minimizer: [
/* Remove Comment, ref→https://webpack.js.org/plugins/terser-webpack-plugin/ */
new TerserPlugin({
terserOptions: {
output: {
comments: false,
},
},
extractComments: false,
}),
],
}
//plugins: [
// new HtmlWebPackPlugin({
// template: "./src/index.html",
// filename: "./index.html"
// })
//]
}];
/*
* 多個進入點與分拆共用模組。
* 應用於 "webpack": "^5.88.2", "webpack-cli": "^5.1.4"
* 但共用模組不是傳統的函式庫提供固定的參數,就算沒有用到也放著。
* 本例 webpack 拆出來的共用模組 shared, common, highorder 其內容是有用到才放入,bundle 混淆後識別代碼名稱也會動態換掉。
*/
const path = require("path");
const TerserPlugin = require('terser-webpack-plugin'); // 用以不產生 LICENSE 宣告檔
const Dotenv = require('dotenv-webpack'); // 用以取得 .env 環境參數
module.exports = {
mode: "production", // development | production
entry: {
common: {
import: './src/common/index.tsx',
dependOn: ['shared'],
},
highorder: {
import: './src/highorder/index.tsx',
dependOn: ['shared', 'common'],
},
home: {
import: "/src/home/app.tsx", //default: "/src/index.js"
dependOn: ['shared','common', 'highorder'],
},
demo001: {
import: '/src/Demo/DEMO001/app.tsx',
dependOn: ['shared', 'common', 'highorder'],
},
demo002: {
import: '/src/Demo/DEMO002/app.tsx',
dependOn: ['shared', 'common', 'highorder'],
},
demo003: {
import: '/src/Demo/DEMO003/app.tsx',
dependOn: ['shared', 'common', 'highorder'],
},
shared: 'lodash', // 動態共享模組
},
output: {
path: path.resolve(__dirname, "../N48MvcReactTpl/Scripts/bundle"), // output folder, default:"./dist"
publicPath: "/",
filename: "[name].bundle.js",
},
optimization: {
runtimeChunk: 'single',
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: false, // 不產生 LICENSE 宣告檔
//exclude: /common|highorder/, // 不進行混淆
}),
],
splitChunks: {
cacheGroups: {
// 動態共享模組 shared: 將所有在 node_modules 中的程式碼打包到 shared.bundle.js。
shared: {
name: 'shared',
test: /[\\/]node_modules[\\/]/,
chunks: 'all',
enforce: true,
},
//// 動態共享模組 common: 將 src\highorder 等共用中的程式碼打包到 common.bundle.js。
//common: {
// name: 'common',
// test: /[\\/]src[\\/](highorder|tools|hooks|atoms|shared)[\\/]/,
// chunks: 'all',
// enforce: true,
//},
},
},
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
module: {
rules: [
{
test: /\.?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
use: [
"style-loader",
"css-loader",
],
},
],
},
plugins: [
new Dotenv({
path: './.env',
systemvars: true,
defaults: true
})
],
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment