From 6dbb1730d853335ba72d75ebe3e5c48f15421859 Mon Sep 17 00:00:00 2001 From: ZLY201 <951711127@qq.com> Date: Sun, 26 Nov 2023 03:13:17 +0800 Subject: [PATCH 1/2] feat: support generate ssr content in devlopment mode --- html/index.html | 4 +- package.json | 6 +- src/modules/Editor/monaco-editor.tsx | 2 +- tools/RspackSSRPlugin.ts | 74 +++++++++++++++++++ .../rspack.base.config.ts | 13 ++-- rspack.config.ts => tools/rspack.config.ts | 24 +++--- .../rspack.ssr.config.ts | 3 +- 7 files changed, 97 insertions(+), 29 deletions(-) create mode 100644 tools/RspackSSRPlugin.ts rename rspack.base.config.ts => tools/rspack.base.config.ts (83%) rename rspack.config.ts => tools/rspack.config.ts (85%) rename rspack.ssr.config.ts => tools/rspack.ssr.config.ts (91%) diff --git a/html/index.html b/html/index.html index 1d6f2e9..8486ac2 100644 --- a/html/index.html +++ b/html/index.html @@ -7,8 +7,6 @@ -
- <%= ROOT_CONTENT %> -
+
{% ROOT_CONTENT %}
diff --git a/package.json b/package.json index 0a9d662..b08c7bb 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,9 @@ "reset": "rm -rf node_modules", "setup": "yarn reset && yarn", "clean": "rm -rf dist", - "dev": "yarn build:ssr && rspack serve --watch", - "build:ssr": "yarn clean && rspack build --config=rspack.ssr.config.ts", - "build": "yarn build:ssr && rspack build && rm -rf dist/ssr", + "dev": "rspack serve --config=tools/rspack.config.ts --watch", + "build:ssr": "rspack build --config=tools/rspack.ssr.config.ts", + "build": "yarn clean && rspack build --config=tools/rspack.config.ts && rm -rf dist/ssr", "lint": "eslint --fix --color --cache --quiet .", "prepare": "husky install" }, diff --git a/src/modules/Editor/monaco-editor.tsx b/src/modules/Editor/monaco-editor.tsx index 2330eb1..6e728c9 100644 --- a/src/modules/Editor/monaco-editor.tsx +++ b/src/modules/Editor/monaco-editor.tsx @@ -147,7 +147,7 @@ const MonacoEditor = withAutoResize( } for (const filename of Object.keys(this.props.raw)) { this.models[filename]?.updateOptions(this.props.setting); - if (!filename.includes('/node_modules/')) { + if (!filename.includes('node_modules')) { validateMonacoModel(this.models[filename]); } } diff --git a/tools/RspackSSRPlugin.ts b/tools/RspackSSRPlugin.ts new file mode 100644 index 0000000..c2c4eba --- /dev/null +++ b/tools/RspackSSRPlugin.ts @@ -0,0 +1,74 @@ +import path from 'path'; +import childProcess from 'child_process'; +import { readFileSync, writeFileSync } from 'fs'; +import { RspackPluginInstance, Compiler } from '@rspack/core'; + +type RspackSSRPluginOptions = { + token: string; + template: string; +}; + +class RspackSSRPlugin implements RspackPluginInstance { + private readonly templateContent: string; + private readonly options: RspackSSRPluginOptions; + constructor(options: RspackSSRPluginOptions) { + this.options = options; + const { template } = options; + this.templateContent = readFileSync(template, { encoding: 'utf-8' }); + } + apply(compiler: Compiler) { + const mode = compiler.options.mode; + const pluginName = RspackSSRPlugin.name; + const tabFunc = + mode === 'development' + ? compiler.hooks.watchRun + : compiler.hooks.beforeRun; + tabFunc.tapAsync(pluginName, (compiler, callback) => { + this.replaceTemplateFile(compiler, callback); + }); + compiler.hooks.done.tap(pluginName, () => + this.recoverTemplateFile(compiler), + ); + } + replaceTemplateFile(compiler: Compiler, callback: () => void) { + const token = this.options.token; + const context = compiler.context; + const mode = compiler.options.mode; + const templateContent = this.templateContent; + const buildProcess = childProcess.spawn('yarn', [ + 'build:ssr', + `--mode=${mode}`, + ]); + buildProcess.stdout.on('data', process.stdout.write); + buildProcess.stderr.on('data', process.stderr.write); + buildProcess.on('close', function (code) { + if (code === 0) { + const ssrFilePath = path.resolve(context, './dist/ssr/ssr.bundle.js'); + // eslint-disable-next-line @typescript-eslint/no-var-requires + const getSSRContent = require(ssrFilePath).default; + delete require.cache[require.resolve(ssrFilePath)]; + const ssrContent = getSSRContent(); + const newTemplateContent = templateContent.replace(token, ssrContent); + writeFileSync( + path.resolve(context, './html/index.html'), + newTemplateContent, + { + encoding: 'utf-8', + }, + ); + callback(); + } else { + throw new Error(`Generate SSR content failed with code ${code}`); + } + }); + } + recoverTemplateFile(compiler: Compiler) { + const context = compiler.context; + const templateContent = this.templateContent; + writeFileSync(path.resolve(context, './html/index.html'), templateContent, { + encoding: 'utf-8', + }); + } +} + +export default RspackSSRPlugin; diff --git a/rspack.base.config.ts b/tools/rspack.base.config.ts similarity index 83% rename from rspack.base.config.ts rename to tools/rspack.base.config.ts index 92e9fa8..2ed677c 100644 --- a/rspack.base.config.ts +++ b/tools/rspack.base.config.ts @@ -3,21 +3,18 @@ import type { Configuration } from '@rspack/cli'; export default function createBaseRspackConfig(): Configuration { return { - context: __dirname, - entry: { - main: './src/main.tsx', - }, + context: path.resolve(__dirname, '..'), output: { - path: path.resolve(__dirname, 'dist'), + path: './dist', filename: '[name].[contenthash:8].bundle.js', chunkFilename: '[name].[contenthash:8].bundle.js', cssChunkFilename: '[name].[contenthash:8].bundle.js', }, resolve: { alias: { - '@config': path.resolve(__dirname, './config'), - '@problems': path.resolve(__dirname, './problems'), - '@src': path.resolve(__dirname, './src'), + '@config': './config', + '@problems': './problems', + '@src': './src', }, }, builtins: { diff --git a/rspack.config.ts b/tools/rspack.config.ts similarity index 85% rename from rspack.config.ts rename to tools/rspack.config.ts index 9fa4609..25343fe 100644 --- a/rspack.config.ts +++ b/tools/rspack.config.ts @@ -1,18 +1,14 @@ -import path from 'path'; import type { Configuration } from '@rspack/cli'; -import { ArcoDesignPlugin } from '@arco-plugins/unplugin-react'; -import { CopyRspackPlugin, DefinePlugin } from '@rspack/core'; import HtmlRspackPlugin from '@rspack/plugin-html'; +import { CopyRspackPlugin, DefinePlugin } from '@rspack/core'; +import { ArcoDesignPlugin } from '@arco-plugins/unplugin-react'; +import RspackSSRPlugin from './RspackSSRPlugin'; import createBaseRspackConfig from './rspack.base.config'; export default function createRspackConfig(): Configuration { const baseConfig = createBaseRspackConfig(); const mode = process.env.NODE_ENV as Configuration['mode']; - // eslint-disable-next-line @typescript-eslint/no-var-requires - const getSSRContent = require( - path.resolve(__dirname, 'dist/ssr/ssr.bundle.js'), - ).default; - const ssrContent = getSSRContent(); + const template = './html/index.html'; return { ...baseConfig, mode, @@ -21,17 +17,21 @@ export default function createRspackConfig(): Configuration { main: './src/main.tsx', }, devtool: mode === 'production' ? false : 'source-map', + watchOptions: { + ignored: template, + }, plugins: [ + new RspackSSRPlugin({ + template, + token: '{% ROOT_CONTENT %}', + }), new HtmlRspackPlugin({ + template, minify: true, sri: 'sha256', inject: 'body', scriptLoading: 'defer', favicon: './assets/favicon.png', - template: './html/index.html', - templateParameters: { - ROOT_CONTENT: ssrContent, - }, }), new CopyRspackPlugin({ patterns: [ diff --git a/rspack.ssr.config.ts b/tools/rspack.ssr.config.ts similarity index 91% rename from rspack.ssr.config.ts rename to tools/rspack.ssr.config.ts index 0feb030..00127f0 100644 --- a/rspack.ssr.config.ts +++ b/tools/rspack.ssr.config.ts @@ -1,4 +1,3 @@ -import path from 'path'; import type { Configuration } from '@rspack/cli'; import { HtmlRspackPlugin, DefinePlugin } from '@rspack/core'; import createBaseRspackConfig from './rspack.base.config'; @@ -14,7 +13,7 @@ export default function createSSRRspackConfig(): Configuration { ssr: './src/ssr.tsx', }, output: { - path: path.resolve(__dirname, 'dist/ssr'), + path: './dist/ssr', filename: 'ssr.bundle.js', library: { type: 'commonjs', From fed5c9eb4c658c886d812211d4df53beb4435105 Mon Sep 17 00:00:00 2001 From: ZLY201 <951711127@qq.com> Date: Thu, 8 Feb 2024 23:20:34 +0800 Subject: [PATCH 2/2] chore: remove ssr build when production --- package.json | 2 +- tools/RspackSSRPlugin.ts | 45 ++++++++++++++++++++++++---------------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index b08c7bb..e8bc525 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "clean": "rm -rf dist", "dev": "rspack serve --config=tools/rspack.config.ts --watch", "build:ssr": "rspack build --config=tools/rspack.ssr.config.ts", - "build": "yarn clean && rspack build --config=tools/rspack.config.ts && rm -rf dist/ssr", + "build": "yarn clean && yarn build:ssr && rspack build --config=tools/rspack.config.ts && rm -rf dist/ssr", "lint": "eslint --fix --color --cache --quiet .", "prepare": "husky install" }, diff --git a/tools/RspackSSRPlugin.ts b/tools/RspackSSRPlugin.ts index c2c4eba..17c4cb2 100644 --- a/tools/RspackSSRPlugin.ts +++ b/tools/RspackSSRPlugin.ts @@ -24,17 +24,21 @@ class RspackSSRPlugin implements RspackPluginInstance { ? compiler.hooks.watchRun : compiler.hooks.beforeRun; tabFunc.tapAsync(pluginName, (compiler, callback) => { - this.replaceTemplateFile(compiler, callback); + this.runSSRBuild(compiler, callback); + }); + tabFunc.tap(pluginName, compiler => { + this.replaceTemplateFile(compiler); }); compiler.hooks.done.tap(pluginName, () => this.recoverTemplateFile(compiler), ); } - replaceTemplateFile(compiler: Compiler, callback: () => void) { - const token = this.options.token; - const context = compiler.context; + runSSRBuild(compiler: Compiler, callback: () => void) { const mode = compiler.options.mode; - const templateContent = this.templateContent; + if (mode !== 'development') { + callback(); + return; + } const buildProcess = childProcess.spawn('yarn', [ 'build:ssr', `--mode=${mode}`, @@ -43,25 +47,30 @@ class RspackSSRPlugin implements RspackPluginInstance { buildProcess.stderr.on('data', process.stderr.write); buildProcess.on('close', function (code) { if (code === 0) { - const ssrFilePath = path.resolve(context, './dist/ssr/ssr.bundle.js'); - // eslint-disable-next-line @typescript-eslint/no-var-requires - const getSSRContent = require(ssrFilePath).default; - delete require.cache[require.resolve(ssrFilePath)]; - const ssrContent = getSSRContent(); - const newTemplateContent = templateContent.replace(token, ssrContent); - writeFileSync( - path.resolve(context, './html/index.html'), - newTemplateContent, - { - encoding: 'utf-8', - }, - ); callback(); } else { throw new Error(`Generate SSR content failed with code ${code}`); } }); } + replaceTemplateFile(compiler: Compiler) { + const token = this.options.token; + const context = compiler.context; + const templateContent = this.templateContent; + const ssrFilePath = path.resolve(context, './dist/ssr/ssr.bundle.js'); + // eslint-disable-next-line @typescript-eslint/no-var-requires + const getSSRContent = require(ssrFilePath).default; + delete require.cache[require.resolve(ssrFilePath)]; + const ssrContent = getSSRContent(); + const newTemplateContent = templateContent.replace(token, ssrContent); + writeFileSync( + path.resolve(context, './html/index.html'), + newTemplateContent, + { + encoding: 'utf-8', + }, + ); + } recoverTemplateFile(compiler: Compiler) { const context = compiler.context; const templateContent = this.templateContent;