diff --git a/web/build/webpack.config.ts b/web/build/webpack.config.ts index f7154ba8..b9b6ef71 100644 --- a/web/build/webpack.config.ts +++ b/web/build/webpack.config.ts @@ -10,6 +10,7 @@ import HtmlWebpackPlugin from 'html-webpack-plugin'; import MiniCssExtractPlugin from 'mini-css-extract-plugin'; import CopyPlugin from 'copy-webpack-plugin'; import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin'; +import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; import fs from 'fs'; import WorkboxPlugin from 'workbox-webpack-plugin'; import { workboxPluginPattern } from './utils'; @@ -26,6 +27,7 @@ const ROOT_PATH = path.resolve(__dirname, '../'); const DIST_PATH = path.resolve(ROOT_PATH, './dist'); const ASSET_PATH = process.env.ASSET_PATH || '/'; const PORT = Number(process.env.PORT || 11011); +const ANALYSIS = process.env.ANALYSIS === 'true'; declare module 'webpack' { interface Configuration { @@ -38,6 +40,99 @@ const NODE_ENV = process.env.NODE_ENV ?? 'production'; const isDev = NODE_ENV === 'development'; const mode = isDev ? 'development' : 'production'; +const plugins: Configuration['plugins'] = [ + new DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify(NODE_ENV), + 'process.env.SERVICE_URL': JSON.stringify(process.env.SERVICE_URL), + 'process.env.VERSION': JSON.stringify( + process.env.VERSION || packageJson.version + ), + }), + new HtmlWebpackPlugin({ + title: 'TailChat', + inject: true, + hash: true, + favicon: path.resolve(ROOT_PATH, './assets/images/logo.svg'), + template: path.resolve(ROOT_PATH, './assets/template.html'), + preloadImage: `data:image/svg+xml;base64,${Buffer.from( + fs.readFileSync(path.resolve(ROOT_PATH, './assets/images/ripple.svg'), { + encoding: 'utf-8', + }) + ).toString('base64')}`, + }), + new CopyPlugin({ + patterns: [ + { + from: path.resolve(ROOT_PATH, '../locales'), + to: 'locales', + }, + { + from: path.resolve(ROOT_PATH, './assets/pwa.webmanifest'), + to: 'pwa.webmanifest', + }, + { + from: path.resolve(ROOT_PATH, './assets/images/logo/'), + to: 'images/logo/', + }, + ], + }) as any, + new MiniCssExtractPlugin({ filename: 'styles-[contenthash].css' }), + new WorkboxPlugin.GenerateSW({ + // https://developers.google.com/web/tools/workbox + // these options encourage the ServiceWorkers to get in there fast + // and not allow any straggling "old" SWs to hang around + clientsClaim: true, + skipWaiting: true, + + // Do not precache images + exclude: [/\.(?:png|jpg|jpeg|svg)$/], + + maximumFileSizeToCacheInBytes: 8 * 1024 * 1024, // 限制最大缓存 8M + + // Define runtime caching rules. + runtimeCaching: [ + { + // Match any request that ends with .png, .jpg, .jpeg or .svg. + urlPattern: /\.(?:png|jpg|jpeg|svg)$/, + + // Apply a cache-first strategy. + handler: 'CacheFirst', + + options: { + // Use a custom cache name. + cacheName: 'images', + + // Only cache 10 images. + expiration: { + maxEntries: 10, + }, + }, + }, + { + // 匹配内置 plugins 以加速 + urlPattern: workboxPluginPattern, + handler: 'CacheFirst', + options: { + cacheName: 'builtin-plugins', + expiration: { + maxAgeSeconds: 1 * 60 * 60, // 1h + }, + cacheableResponse: { + // 只缓存js, 防止404后台直接fallback到html + headers: { + 'content-type': 'application/javascript; charset=utf-8', + }, + }, + }, + }, + ], + }), +]; + +if (ANALYSIS) { + plugins.push(new BundleAnalyzerPlugin() as any); +} + const config: Configuration = { mode, entry: { @@ -118,94 +213,7 @@ const config: Configuration = { }), ], }, - plugins: [ - new DefinePlugin({ - 'process.env.NODE_ENV': JSON.stringify(NODE_ENV), - 'process.env.SERVICE_URL': JSON.stringify(process.env.SERVICE_URL), - 'process.env.VERSION': JSON.stringify( - process.env.VERSION || packageJson.version - ), - }), - new HtmlWebpackPlugin({ - title: 'TailChat', - inject: true, - hash: true, - favicon: path.resolve(ROOT_PATH, './assets/images/logo.svg'), - template: path.resolve(ROOT_PATH, './assets/template.html'), - preloadImage: `data:image/svg+xml;base64,${Buffer.from( - fs.readFileSync(path.resolve(ROOT_PATH, './assets/images/ripple.svg'), { - encoding: 'utf-8', - }) - ).toString('base64')}`, - }), - new CopyPlugin({ - patterns: [ - { - from: path.resolve(ROOT_PATH, '../locales'), - to: 'locales', - }, - { - from: path.resolve(ROOT_PATH, './assets/pwa.webmanifest'), - to: 'pwa.webmanifest', - }, - { - from: path.resolve(ROOT_PATH, './assets/images/logo/'), - to: 'images/logo/', - }, - ], - }) as any, - new MiniCssExtractPlugin({ filename: 'styles-[contenthash].css' }), - new WorkboxPlugin.GenerateSW({ - // https://developers.google.com/web/tools/workbox - // these options encourage the ServiceWorkers to get in there fast - // and not allow any straggling "old" SWs to hang around - clientsClaim: true, - skipWaiting: true, - - // Do not precache images - exclude: [/\.(?:png|jpg|jpeg|svg)$/], - - maximumFileSizeToCacheInBytes: 8 * 1024 * 1024, // 限制最大缓存 8M - - // Define runtime caching rules. - runtimeCaching: [ - { - // Match any request that ends with .png, .jpg, .jpeg or .svg. - urlPattern: /\.(?:png|jpg|jpeg|svg)$/, - - // Apply a cache-first strategy. - handler: 'CacheFirst', - - options: { - // Use a custom cache name. - cacheName: 'images', - - // Only cache 10 images. - expiration: { - maxEntries: 10, - }, - }, - }, - { - // 匹配内置 plugins 以加速 - urlPattern: workboxPluginPattern, - handler: 'CacheFirst', - options: { - cacheName: 'builtin-plugins', - expiration: { - maxAgeSeconds: 1 * 60 * 60, // 1h - }, - cacheableResponse: { - // 只缓存js, 防止404后台直接fallback到html - headers: { - 'content-type': 'application/javascript; charset=utf-8', - }, - }, - }, - }, - ], - }), - ], + plugins, }; export default config; diff --git a/web/package.json b/web/package.json index 0a9b2bde..75d2d684 100644 --- a/web/package.json +++ b/web/package.json @@ -67,6 +67,7 @@ "@types/react-virtualized": "^9.21.14", "@types/react-virtualized-auto-sizer": "^1.0.1", "@types/webpack": "^5.28.0", + "@types/webpack-bundle-analyzer": "^4.4.1", "@types/webpack-dev-server": "^4.3.1", "@types/workbox-webpack-plugin": "^5.1.8", "autoprefixer": "^10.2.6", @@ -91,6 +92,7 @@ "typescript": "^4.3.4", "url-loader": "^4.1.1", "webpack": "^5.58.2", + "webpack-bundle-analyzer": "^4.5.0", "webpack-cli": "^4.9.1", "webpack-dev-server": "^4.3.1", "workbox-webpack-plugin": "^6.3.0" diff --git a/yarn.lock b/yarn.lock index 96f538b8..6dd68312 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1565,6 +1565,11 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@polka/url@^1.0.0-next.20": + version "1.0.0-next.21" + resolved "https://registry.npmmirror.com/@polka/url/download/@polka/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" + integrity sha1-XeWiOFo1MJQn9gEZkrVEUU1VmqE= + "@reduxjs/toolkit@^1.6.0": version "1.6.0" resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.6.0.tgz#0a17c6941c57341f8b31e982352b495ab69d5add" @@ -2209,6 +2214,15 @@ resolved "https://registry.nlark.com/@types/trusted-types/download/@types/trusted-types-2.0.2.tgz?cache=0&sync_timestamp=1629710736958&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Ftrusted-types%2Fdownload%2F%40types%2Ftrusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756" integrity sha1-/CWtmUO8rBHM64Fo208nXg5y51Y= +"@types/webpack-bundle-analyzer@^4.4.1": + version "4.4.1" + resolved "https://registry.npmmirror.com/@types/webpack-bundle-analyzer/download/@types/webpack-bundle-analyzer-4.4.1.tgz#bcc2501be10c8cdd1d170bc6b7847b3321f20440" + integrity sha1-vMJQG+EMjN0dFwvGt4R7MyHyBEA= + dependencies: + "@types/node" "*" + tapable "^2.2.0" + webpack "^5" + "@types/webpack-dev-middleware@*": version "5.0.2" resolved "https://registry.nlark.com/@types/webpack-dev-middleware/download/@types/webpack-dev-middleware-5.0.2.tgz?cache=0&sync_timestamp=1629709766577&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fwebpack-dev-middleware%2Fdownload%2F%40types%2Fwebpack-dev-middleware-5.0.2.tgz#0f66566c2ca7d484891b4552c8a7b64a3044e3e2" @@ -4532,6 +4546,11 @@ dts-generator@^3.0.0: glob "^7.1.3" mkdirp "^0.5.1" +duplexer@^0.1.2: + version "0.1.2" + resolved "https://registry.npm.taobao.org/duplexer/download/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha1-Or5DrvODX4rgd9E23c4PJ2sEAOY= + duplexify@^3.6.0: version "3.7.1" resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" @@ -5474,6 +5493,13 @@ gulp-sort@^2.0.0: dependencies: through2 "^2.0.1" +gzip-size@^6.0.0: + version "6.0.0" + resolved "https://registry.nlark.com/gzip-size/download/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" + integrity sha1-BlNn/VDCOcBnHLy61b4+LusQ5GI= + dependencies: + duplexer "^0.1.2" + handle-thing@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" @@ -7387,6 +7413,11 @@ mime@1.6.0, mime@^1.4.1: resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +mime@^2.3.1: + version "2.6.0" + resolved "https://registry.npmmirror.com/mime/download/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha1-oqaCqVzU0MsdYlfij4PafjWAA2c= + mime@^2.4.6: version "2.5.2" resolved "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" @@ -7863,6 +7894,11 @@ opencollective@^1.0.3: node-fetch "1.6.3" opn "4.0.2" +opener@^1.5.2: + version "1.5.2" + resolved "https://registry.nlark.com/opener/download/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" + integrity sha1-XTfh81B3udysQwE3InGv3rKhNZg= + opn@4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz#7abc22e644dff63b0a96d5ab7f2790c0f01abc95" @@ -9867,6 +9903,15 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" +sirv@^1.0.7: + version "1.0.18" + resolved "https://registry.npmmirror.com/sirv/download/sirv-1.0.18.tgz?cache=0&sync_timestamp=1634320242028&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fsirv%2Fdownload%2Fsirv-1.0.18.tgz#105fab52fb656ce8a2bebbf36b11052005952899" + integrity sha1-EF+rUvtlbOiivrvzaxEFIAWVKJk= + dependencies: + "@polka/url" "^1.0.0-next.20" + mime "^2.3.1" + totalist "^1.0.0" + sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" @@ -10568,6 +10613,11 @@ toposort@^2.0.2: resolved "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" integrity sha1-riF2gXXRVZ1IvvNUILL0li8JwzA= +totalist@^1.0.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/totalist/download/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" + integrity sha1-pNZaPlRlF3AePlw3pHpwrJf+Vt8= + tough-cookie@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" @@ -11081,6 +11131,21 @@ webidl-conversions@^6.1.0: resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== +webpack-bundle-analyzer@^4.5.0: + version "4.5.0" + resolved "https://registry.npmmirror.com/webpack-bundle-analyzer/download/webpack-bundle-analyzer-4.5.0.tgz?cache=0&sync_timestamp=1634019948189&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fwebpack-bundle-analyzer%2Fdownload%2Fwebpack-bundle-analyzer-4.5.0.tgz#1b0eea2947e73528754a6f9af3e91b2b6e0f79d5" + integrity sha1-Gw7qKUfnNSh1Sm+a8+kbK24PedU= + dependencies: + acorn "^8.0.4" + acorn-walk "^8.0.0" + chalk "^4.1.0" + commander "^7.2.0" + gzip-size "^6.0.0" + lodash "^4.17.20" + opener "^1.5.2" + sirv "^1.0.7" + ws "^7.3.1" + webpack-cli@^4.9.1: version "4.9.1" resolved "https://registry.npmmirror.com/webpack-cli/download/webpack-cli-4.9.1.tgz?cache=0&sync_timestamp=1634556269527&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fwebpack-cli%2Fdownload%2Fwebpack-cli-4.9.1.tgz#b64be825e2d1b130f285c314caa3b1ba9a4632b3" @@ -11534,6 +11599,11 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" +ws@^7.3.1: + version "7.5.5" + resolved "https://registry.npmmirror.com/ws/download/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881" + integrity sha1-i0vEr1GM+r0Ec65PmRRCh7M+uIE= + ws@^7.4.5: version "7.5.1" resolved "https://registry.npmjs.org/ws/-/ws-7.5.1.tgz#44fc000d87edb1d9c53e51fbc69a0ac1f6871d66"