From 40f07b1b9f50742c3b2621ab525086d17a2e2ab0 Mon Sep 17 00:00:00 2001 From: "Mr.Hope" Date: Thu, 14 May 2026 15:59:02 +0800 Subject: [PATCH 01/13] chore: tweaks --- .vscode/settings.json | 1 + packages/bundler-rspack/README.md | 12 + packages/bundler-rspack/package.json | 66 +++++ packages/bundler-rspack/src/build/build.ts | 110 ++++++++ .../src/build/createClientConfig.ts | 96 +++++++ .../src/build/createClientPlugin.ts | 110 ++++++++ .../src/build/createServerConfig.ts | 45 +++ packages/bundler-rspack/src/build/index.ts | 1 + .../bundler-rspack/src/build/renderPage.ts | 83 ++++++ .../src/build/renderPagePrefetchLinks.ts | 39 +++ .../src/build/renderPagePreloadLinks.ts | 45 +++ .../src/build/renderPageScripts.ts | 23 ++ .../src/build/renderPageStyles.ts | 24 ++ .../src/build/resolveClientManifestMeta.ts | 46 +++ .../src/build/resolveFileMeta.ts | 16 ++ .../src/build/resolveFileMetaType.ts | 21 ++ .../src/build/resolvePageClientFilesMeta.ts | 19 ++ packages/bundler-rspack/src/build/types.ts | 39 +++ .../src/config/createBaseConfig.ts | 69 +++++ .../src/config/createClientBaseConfig.ts | 32 +++ .../src/config/handleDevtool.ts | 23 ++ .../bundler-rspack/src/config/handleEntry.ts | 25 ++ .../bundler-rspack/src/config/handleMode.ts | 17 ++ .../bundler-rspack/src/config/handleModule.ts | 48 ++++ .../src/config/handleModuleAssets.ts | 48 ++++ .../src/config/handleModuleJs.ts | 58 ++++ .../src/config/handleModulePug.ts | 12 + .../src/config/handleModuleStyles.ts | 130 +++++++++ .../src/config/handleModuleTs.ts | 25 ++ .../src/config/handleModuleVue.ts | 71 +++++ .../bundler-rspack/src/config/handleNode.ts | 12 + .../src/config/handleOtherOptions.ts | 51 ++++ .../src/config/handlePluginDefine.ts | 49 ++++ .../src/config/handleResolve.ts | 53 ++++ packages/bundler-rspack/src/config/index.ts | 2 + .../src/config/resolveEsbuildLoaderOptions.ts | 23 ++ .../bundler-rspack/src/dev/createDevConfig.ts | 28 ++ .../src/dev/createDevServerConfig.ts | 50 ++++ packages/bundler-rspack/src/dev/dev.ts | 87 ++++++ packages/bundler-rspack/src/dev/index.ts | 1 + .../src/dev/trailingSlashMiddleware.ts | 26 ++ packages/bundler-rspack/src/index.ts | 5 + .../src/loaders/vuepressMarkdownLoader.cts | 3 + .../src/loaders/vuepressMarkdownLoader.ts | 39 +++ .../src/loaders/vuepressSsrLoader.cts | 3 + .../src/loaders/vuepressSsrLoader.ts | 29 ++ .../bundler-rspack/src/resolveRspackConfig.ts | 38 +++ packages/bundler-rspack/src/rspackBundler.ts | 11 + packages/bundler-rspack/src/types.ts | 144 ++++++++++ packages/bundler-rspack/tsdown.config.ts | 25 ++ pnpm-lock.yaml | 262 +++++++++++++++++- 51 files changed, 2282 insertions(+), 13 deletions(-) create mode 100644 packages/bundler-rspack/README.md create mode 100644 packages/bundler-rspack/package.json create mode 100644 packages/bundler-rspack/src/build/build.ts create mode 100644 packages/bundler-rspack/src/build/createClientConfig.ts create mode 100644 packages/bundler-rspack/src/build/createClientPlugin.ts create mode 100644 packages/bundler-rspack/src/build/createServerConfig.ts create mode 100644 packages/bundler-rspack/src/build/index.ts create mode 100644 packages/bundler-rspack/src/build/renderPage.ts create mode 100644 packages/bundler-rspack/src/build/renderPagePrefetchLinks.ts create mode 100644 packages/bundler-rspack/src/build/renderPagePreloadLinks.ts create mode 100644 packages/bundler-rspack/src/build/renderPageScripts.ts create mode 100644 packages/bundler-rspack/src/build/renderPageStyles.ts create mode 100644 packages/bundler-rspack/src/build/resolveClientManifestMeta.ts create mode 100644 packages/bundler-rspack/src/build/resolveFileMeta.ts create mode 100644 packages/bundler-rspack/src/build/resolveFileMetaType.ts create mode 100644 packages/bundler-rspack/src/build/resolvePageClientFilesMeta.ts create mode 100644 packages/bundler-rspack/src/build/types.ts create mode 100644 packages/bundler-rspack/src/config/createBaseConfig.ts create mode 100644 packages/bundler-rspack/src/config/createClientBaseConfig.ts create mode 100644 packages/bundler-rspack/src/config/handleDevtool.ts create mode 100644 packages/bundler-rspack/src/config/handleEntry.ts create mode 100644 packages/bundler-rspack/src/config/handleMode.ts create mode 100644 packages/bundler-rspack/src/config/handleModule.ts create mode 100644 packages/bundler-rspack/src/config/handleModuleAssets.ts create mode 100644 packages/bundler-rspack/src/config/handleModuleJs.ts create mode 100644 packages/bundler-rspack/src/config/handleModulePug.ts create mode 100644 packages/bundler-rspack/src/config/handleModuleStyles.ts create mode 100644 packages/bundler-rspack/src/config/handleModuleTs.ts create mode 100644 packages/bundler-rspack/src/config/handleModuleVue.ts create mode 100644 packages/bundler-rspack/src/config/handleNode.ts create mode 100644 packages/bundler-rspack/src/config/handleOtherOptions.ts create mode 100644 packages/bundler-rspack/src/config/handlePluginDefine.ts create mode 100644 packages/bundler-rspack/src/config/handleResolve.ts create mode 100644 packages/bundler-rspack/src/config/index.ts create mode 100644 packages/bundler-rspack/src/config/resolveEsbuildLoaderOptions.ts create mode 100644 packages/bundler-rspack/src/dev/createDevConfig.ts create mode 100644 packages/bundler-rspack/src/dev/createDevServerConfig.ts create mode 100644 packages/bundler-rspack/src/dev/dev.ts create mode 100644 packages/bundler-rspack/src/dev/index.ts create mode 100644 packages/bundler-rspack/src/dev/trailingSlashMiddleware.ts create mode 100644 packages/bundler-rspack/src/index.ts create mode 100644 packages/bundler-rspack/src/loaders/vuepressMarkdownLoader.cts create mode 100644 packages/bundler-rspack/src/loaders/vuepressMarkdownLoader.ts create mode 100644 packages/bundler-rspack/src/loaders/vuepressSsrLoader.cts create mode 100644 packages/bundler-rspack/src/loaders/vuepressSsrLoader.ts create mode 100644 packages/bundler-rspack/src/resolveRspackConfig.ts create mode 100644 packages/bundler-rspack/src/rspackBundler.ts create mode 100644 packages/bundler-rspack/src/types.ts create mode 100644 packages/bundler-rspack/tsdown.config.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index b2caabf7db..58b417f6be 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -31,6 +31,7 @@ "mdit", "prefetch", "preload", + "rspack", "slugify", "tinyglobby", "unmount", diff --git a/packages/bundler-rspack/README.md b/packages/bundler-rspack/README.md new file mode 100644 index 0000000000..964763a99f --- /dev/null +++ b/packages/bundler-rspack/README.md @@ -0,0 +1,12 @@ +# @vuepress/bundler-rspack + +[![npm](https://badgen.net/npm/v/@vuepress/bundler-rspack/next)](https://www.npmjs.com/package/@vuepress/bundler-rspack) +[![license](https://badgen.net/github/license/vuepress/core)](https://github.com/vuepress/core/blob/main/LICENSE) + +## Documentation + +https://vuepress.vuejs.org + +## License + +[MIT](https://github.com/vuepress/core/blob/main/LICENSE) diff --git a/packages/bundler-rspack/package.json b/packages/bundler-rspack/package.json new file mode 100644 index 0000000000..d56c5c587d --- /dev/null +++ b/packages/bundler-rspack/package.json @@ -0,0 +1,66 @@ +{ + "name": "@vuepress/bundler-rspack", + "version": "2.0.0-rc.29", + "description": "Bundler rspack package of VuePress", + "keywords": [ + "bundler", + "rspack", + "vuepress", + "vuepress-bundler" + ], + "homepage": "https://github.com/vuepress", + "bugs": { + "url": "https://github.com/vuepress/core/issues" + }, + "license": "MIT", + "author": "meteorlxy", + "repository": { + "type": "git", + "url": "git+https://github.com/vuepress/core.git" + }, + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "imports": { + "#vuepress-markdown-loader": "./dist/vuepress-markdown-loader.cjs", + "#vuepress-ssr-loader": "./dist/vuepress-ssr-loader.cjs" + }, + "exports": { + ".": "./dist/index.js", + "./package.json": "./package.json" + }, + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "tsdown", + "clean": "rimraf dist" + }, + "dependencies": { + "@rspack/core": "^2.0.3", + "@rspack/dev-server": "^2.0.1", + "@types/express": "^4.17.25", + "@vuepress/bundlerutils": "workspace:*", + "@vuepress/client": "workspace:*", + "@vuepress/core": "workspace:*", + "@vuepress/shared": "workspace:*", + "@vuepress/utils": "workspace:*", + "autoprefixer": "^10.5.0", + "css-loader": "^7.1.4", + "esbuild-loader": "~4.4.3", + "express": "^4.22.1", + "html-webpack-plugin": "^5.6.7", + "postcss": "^8.5.14", + "postcss-loader": "^8.2.1", + "rspack-chain": "^2.0.1", + "rspack-merge": "^0.1.1", + "style-loader": "^4.0.0", + "vue": "catalog:vue", + "vue-loader": "^17.4.2", + "vue-router": "catalog:vue" + } +} diff --git a/packages/bundler-rspack/src/build/build.ts b/packages/bundler-rspack/src/build/build.ts new file mode 100644 index 0000000000..866931f643 --- /dev/null +++ b/packages/bundler-rspack/src/build/build.ts @@ -0,0 +1,110 @@ +import { createVueServerApp, getSsrTemplate } from '@vuepress/bundlerutils' +import type { App, Bundler } from '@vuepress/core' +import { colors, debug, fs, logger, withSpinner } from '@vuepress/utils' +import type { MultiConfiguration } from 'webpack' +import webpack from 'webpack' + +import { resolveRspackConfig } from '../resolveRspackConfig.js' +import type { RspackBundlerOptions } from '../types.js' +import { + CLIENT_MANIFEST_FILENAME, + createClientConfig, +} from './createClientConfig.js' +import { createServerConfig } from './createServerConfig.js' +import { renderPage } from './renderPage.js' +import { resolveClientManifestMeta } from './resolveClientManifestMeta.js' +import type { ClientManifest } from './types.js' + +const log = debug('vuepress:bundler-webpack/build') + +export const build = async ( + options: RspackBundlerOptions, + app: App, +): ReturnType => { + // plugin hook: extendsBundlerOptions + await app.pluginApi.hooks.extendsBundlerOptions.process(options, app) + + // webpack compile + log('compiling start') + await withSpinner('Compiling with webpack')(async () => { + // create webpack config + const clientConfig = resolveRspackConfig({ + config: await createClientConfig(app, options), + options, + isServer: false, + isBuild: true, + }) + const serverConfig = resolveRspackConfig({ + config: await createServerConfig(app, options), + options, + isServer: true, + isBuild: true, + }) + + await new Promise((resolve, reject) => { + webpack( + [clientConfig, serverConfig] as MultiConfiguration, + (err, stats) => { + if (err) { + reject(err) + } else if (stats?.hasErrors()) { + stats.toJson().errors?.forEach((item) => { + logger.error(item) + }) + reject(new Error('Failed to compile with errors')) + } else { + if (stats?.hasWarnings()) { + stats.toJson().warnings?.forEach((warning) => { + logger.warn(warning) + }) + } + resolve() + } + }, + ) + }) + }) + log('compiling finish') + + // render pages + await withSpinner(`Rendering ${app.pages.length} pages`)(async (spinner) => { + // load the client manifest file + const clientManifestPath = app.dir.temp(CLIENT_MANIFEST_FILENAME) + const clientManifest = (await fs.readJson( + clientManifestPath, + )) as ClientManifest + + // resolve client files meta + const { initialFilesMeta, asyncFilesMeta, moduleFilesMetaMap } = + resolveClientManifestMeta(clientManifest) + + // create vue ssr app and get ssr template + const { vueApp, vueRouter } = await createVueServerApp( + app.dir.temp('.server/app.cjs'), + ) + const ssrTemplate = await getSsrTemplate(app) + + // pre-render pages to html files + for (const page of app.pages) { + if (spinner) { + spinner.text = `Rendering pages ${colors.magenta(page.path)}` + } + await renderPage({ + app, + page, + vueApp, + vueRouter, + ssrTemplate, + initialFilesMeta, + asyncFilesMeta, + moduleFilesMetaMap, + }) + } + }) + + // keep the server bundle files in debug mode + if (!app.env.isDebug) { + // remove server temp directory after pages rendered + await fs.remove(app.dir.temp('.server')) + } +} diff --git a/packages/bundler-rspack/src/build/createClientConfig.ts b/packages/bundler-rspack/src/build/createClientConfig.ts new file mode 100644 index 0000000000..faaf5fc0dc --- /dev/null +++ b/packages/bundler-rspack/src/build/createClientConfig.ts @@ -0,0 +1,96 @@ +import { + CopyRspackPlugin, + CssExtractRspackPlugin, + LightningCssMinimizerRspackPlugin, +} from '@rspack/core' +import type { App } from '@vuepress/core' +import { fs } from '@vuepress/utils' +import type { Module } from 'webpack' +import type { Config } from 'webpack-v5-chain' + +import { createClientBaseConfig } from '../config/index.js' +import type { RspackBundlerOptions } from '../types.js' +import { createClientPlugin } from './createClientPlugin.js' + +/** + * Filename of the client manifest file that generated by client plugin + */ +export const CLIENT_MANIFEST_FILENAME = '.server/client-manifest.json' + +export const createClientConfig = async ( + app: App, + options: RspackBundlerOptions, +): Promise => { + const config = await createClientBaseConfig({ + app, + options, + isBuild: true, + }) + + // vuepress client plugin, handle client assets info for ssr + config + .plugin('vuepress-client') + .use(createClientPlugin(app.dir.temp(CLIENT_MANIFEST_FILENAME))) + + // copy files from public dir to dest dir + if (fs.pathExistsSync(app.dir.public())) { + config.plugin('copy').use(CopyRspackPlugin, [ + { + patterns: [{ from: app.dir.public(), to: app.dir.dest() }], + }, + ]) + } + + // optimizations for production mode + // css-extract + config.plugin('css-extract').use(CssExtractRspackPlugin, [ + { + filename: 'assets/css/styles.[chunkhash:8].css', + }, + ]) + + config.optimization.splitChunks({ + cacheGroups: { + // ensure all css are extracted together. + // since most of the CSS will be from the theme and very little + // CSS will be from async chunks + styles: { + idHint: 'styles', + // necessary to ensure async chunks are also extracted + test: (m: Module) => m.type.includes('css/mini-extract'), + chunks: 'all', + enforce: true, + reuseExistingChunk: true, + }, + // extract external library to a standalone chunk + vendor: { + idHint: 'vendor', + test: /node_modules/, + chunks: 'all', + priority: -10, + reuseExistingChunk: true, + }, + }, + }) + + // enable runtimeChunk + config.optimization.runtimeChunk(true) + + // minimize + config.optimization.minimize(true) + + // minimizer + config.optimization.set('minimizer', [ + // keep the default minimizer + '...', + // add css minimizer + new LightningCssMinimizerRspackPlugin(), + ]) + + // disable performance hints + if (!app.env.isDebug) { + config.performance.hints(false) + } + + return config +} diff --git a/packages/bundler-rspack/src/build/createClientPlugin.ts b/packages/bundler-rspack/src/build/createClientPlugin.ts new file mode 100644 index 0000000000..8e39036dd0 --- /dev/null +++ b/packages/bundler-rspack/src/build/createClientPlugin.ts @@ -0,0 +1,110 @@ +import { fs } from '@vuepress/utils' +import type { StatsModule, WebpackPluginInstance } from 'webpack' + +import type { ClientManifest } from './types.js' + +const isJS = (file: string): boolean => /\.js(\?[^.]+)?$/.test(file) + +const isCSS = (file: string): boolean => /\.css(\?[^.]+)?$/.test(file) + +/** + * Vuepress client plugin + * + * Collecting webpack bundled files info for SSR + */ +export const createClientPlugin = ( + outputFile: string, +): WebpackPluginInstance => { + const clientPlugin: WebpackPluginInstance = { + apply(compiler) { + compiler.hooks.emit.tapPromise( + 'vuepress-client-plugin', + async (compilation) => { + // get webpack stats object + const { + assets = [], + modules = [], + entrypoints = {}, + chunks = [], + } = compilation.getStats().toJson() + + // get all files + const allFiles = assets.map((a) => a.name) + + // get initial entry files + const initialFiles = Object.keys(entrypoints) + .flatMap( + (name) => + entrypoints[name].assets?.map((item) => item.name) ?? [], + ) + .filter((file) => isJS(file) || isCSS(file)) + + // get files that should be loaded asynchronously + // i.e. script and style files that are not included in the initial entry files + const asyncFiles = allFiles.filter( + (file) => + (isJS(file) || isCSS(file)) && !initialFiles.includes(file), + ) + + // get asset modules + const assetModules = modules.filter( + (m): m is Required> & StatsModule => + Boolean(m.assets?.length), + ) + + // get modules for client manifest + const manifestModules: ClientManifest['modules'] = {} + + const fileToIndex = (file: number | string): number => + allFiles.indexOf(file.toString()) + + modules.forEach((m) => { + // ignore modules duplicated in multiple chunks + if (m.chunks?.length !== 1) { + return + } + + const cid = m.chunks[0] + const chunk = chunks.find((c) => c.id === cid) + + if (!chunk?.files) { + return + } + + // remove appended hash of module identifier + // which is the request string of the module + const request = m.identifier?.replace(/\|\w+$/, '') + + // get chunk files index + const files = [...chunk.files.map(fileToIndex)] + + // find all asset modules associated with the same chunk + assetModules.forEach((item) => { + if (item.chunks?.some((id) => id === cid)) { + // get asset files + files.push(...item.assets.map(fileToIndex)) + } + }) + + // map the module request to files index + if (request) manifestModules[request] = files + }) + + // generate client manifest json file + const clientManifest: ClientManifest = { + all: allFiles, + initial: initialFiles, + async: asyncFiles, + modules: manifestModules, + } + + const clientManifestJson = JSON.stringify(clientManifest, null, 2) + + await fs.outputFile(outputFile, clientManifestJson) + }, + ) + }, + } + + return clientPlugin +} diff --git a/packages/bundler-rspack/src/build/createServerConfig.ts b/packages/bundler-rspack/src/build/createServerConfig.ts new file mode 100644 index 0000000000..76a39dfe5a --- /dev/null +++ b/packages/bundler-rspack/src/build/createServerConfig.ts @@ -0,0 +1,45 @@ +import type { App } from '@vuepress/core' +import type { Config } from 'webpack-v5-chain' + +import { createBaseConfig } from '../config/index.js' +import type { RspackBundlerOptions } from '../types.js' + +export const createServerConfig = async ( + app: App, + options: RspackBundlerOptions, +): Promise => { + const isBuild = true + const isServer = true + + const config = await createBaseConfig({ + app, + options, + isBuild, + isServer, + }) + + // server output + // remove after pages rendered + config.output + .path(app.dir.temp('.server')) + .filename('app.cjs') + .publicPath(app.options.base) + .libraryTarget('commonjs2') + + // set target to node + // vue-loader will use compiler-ssr internally + config.target('node') + + // set externals + // externalize vue in ssr mode, because we need to import `'vue/server-renderer'` in node side + // for ssr usage, then we also need vue as peer-dependency when using pnpm + config.externals(['vue']) + + // devtool + config.devtool('source-map') + + // do not need to minimize server bundle + config.optimization.minimize(false) + + return config +} diff --git a/packages/bundler-rspack/src/build/index.ts b/packages/bundler-rspack/src/build/index.ts new file mode 100644 index 0000000000..33b5713ae3 --- /dev/null +++ b/packages/bundler-rspack/src/build/index.ts @@ -0,0 +1 @@ +export * from './build.js' diff --git a/packages/bundler-rspack/src/build/renderPage.ts b/packages/bundler-rspack/src/build/renderPage.ts new file mode 100644 index 0000000000..2608faff9e --- /dev/null +++ b/packages/bundler-rspack/src/build/renderPage.ts @@ -0,0 +1,83 @@ +import type { PageSSRContext } from '@vuepress/bundlerutils' +import { renderPageToString } from '@vuepress/bundlerutils' +import type { App, Page } from '@vuepress/core' +import { fs, renderHead } from '@vuepress/utils' +import type { App as VueApp } from 'vue' +import type { Router } from 'vue-router' + +import { renderPagePrefetchLinks } from './renderPagePrefetchLinks.js' +import { renderPagePreloadLinks } from './renderPagePreloadLinks.js' +import { renderPageScripts } from './renderPageScripts.js' +import { renderPageStyles } from './renderPageStyles.js' +import { resolvePageClientFilesMeta } from './resolvePageClientFilesMeta.js' +import type { FileMeta, ModuleFilesMetaMap } from './types.js' + +interface WebpackPageSSRContext extends PageSSRContext { + /** + * Injected by vuepress-ssr-loader + * + * Store the module request of components that used by current page + */ + _registeredComponents: Set +} + +/** + * Render page to html file, return the html file path + */ +export const renderPage = async ({ + app, + page, + vueApp, + vueRouter, + ssrTemplate, + initialFilesMeta, + asyncFilesMeta, + moduleFilesMetaMap, +}: { + app: App + page: Page + vueApp: VueApp + vueRouter: Router + ssrTemplate: string + initialFilesMeta: FileMeta[] + asyncFilesMeta: FileMeta[] + moduleFilesMetaMap: ModuleFilesMetaMap +}): Promise => { + // render current page to string + const { ssrContext, ssrString } = + await renderPageToString({ + page, + vueApp, + vueRouter, + ssrContextInit: { _registeredComponents: new Set() }, + }) + + // resolve client files that used by this page + const pageClientFilesMeta = resolvePageClientFilesMeta({ + moduleRequests: Array.from(ssrContext._registeredComponents), + moduleFilesMetaMap, + }) + + // generate html string + const html = await app.options.templateBuildRenderer(ssrTemplate, { + content: ssrString, + head: ssrContext.head.map(renderHead).join(''), + lang: ssrContext.lang, + prefetch: renderPagePrefetchLinks({ + app, + asyncFilesMeta, + pageClientFilesMeta, + }), + preload: renderPagePreloadLinks({ + app, + initialFilesMeta, + pageClientFilesMeta, + }), + scripts: renderPageScripts({ app, initialFilesMeta, pageClientFilesMeta }), + styles: renderPageStyles({ app, initialFilesMeta, pageClientFilesMeta }), + version: app.version, + }) + + // write html file + await fs.outputFile(page.htmlFilePath, html) +} diff --git a/packages/bundler-rspack/src/build/renderPagePrefetchLinks.ts b/packages/bundler-rspack/src/build/renderPagePrefetchLinks.ts new file mode 100644 index 0000000000..810fd115d0 --- /dev/null +++ b/packages/bundler-rspack/src/build/renderPagePrefetchLinks.ts @@ -0,0 +1,39 @@ +import type { App } from '@vuepress/core' + +import type { FileMeta } from './types.js' + +/** + * Render prefetch links of current page + */ +export const renderPagePrefetchLinks = ({ + app, + asyncFilesMeta, + pageClientFilesMeta, +}: { + app: App + asyncFilesMeta: FileMeta[] + pageClientFilesMeta: FileMeta[] +}): string => { + // shouldPrefetch option + const { shouldPrefetch } = app.options + + // do not render prefetch links + if (shouldPrefetch === false) { + return '' + } + + // async files excluding files used by current page should be prefetch + const prefetchFilesMeta = asyncFilesMeta.filter( + ({ file }) => !pageClientFilesMeta.some((f) => f.file === file), + ) + + return prefetchFilesMeta + .map(({ file, type }) => { + // user wants to explicitly control what to prefetch + if (shouldPrefetch !== true && !shouldPrefetch(file, type)) { + return '' + } + return `` + }) + .join('') +} diff --git a/packages/bundler-rspack/src/build/renderPagePreloadLinks.ts b/packages/bundler-rspack/src/build/renderPagePreloadLinks.ts new file mode 100644 index 0000000000..e3dda92dee --- /dev/null +++ b/packages/bundler-rspack/src/build/renderPagePreloadLinks.ts @@ -0,0 +1,45 @@ +import type { App } from '@vuepress/core' + +import type { FileMeta } from './types.js' + +/** + * Render preload links of current page + */ +export const renderPagePreloadLinks = ({ + app, + initialFilesMeta, + pageClientFilesMeta, +}: { + app: App + initialFilesMeta: FileMeta[] + pageClientFilesMeta: FileMeta[] +}): string => { + // shouldPreload option + const { shouldPreload } = app.options + + // do not render preload links + if (shouldPreload === false) { + return '' + } + + // initial files and files used by current page should be preload + const preloadFilesMeta = [...initialFilesMeta, ...pageClientFilesMeta] + + return preloadFilesMeta + .map(({ file, extension, type }) => { + // by default, we only preload scripts or css + if (shouldPreload === true && type !== 'script' && type !== 'style') { + return '' + } + + // user wants to explicitly control what to preload + if (shouldPreload !== true && !shouldPreload(file, type)) { + return '' + } + + return `` + }) + .join('') +} diff --git a/packages/bundler-rspack/src/build/renderPageScripts.ts b/packages/bundler-rspack/src/build/renderPageScripts.ts new file mode 100644 index 0000000000..09ca2c619f --- /dev/null +++ b/packages/bundler-rspack/src/build/renderPageScripts.ts @@ -0,0 +1,23 @@ +import type { App } from '@vuepress/core' + +import type { FileMeta } from './types.js' + +/** + * Render scripts of current page + */ +export const renderPageScripts = ({ + app, + initialFilesMeta, + pageClientFilesMeta, +}: { + app: App + initialFilesMeta: FileMeta[] + pageClientFilesMeta: FileMeta[] +}): string => + // include initial JS files and other async JS files of current page + [...pageClientFilesMeta, ...initialFilesMeta] + .filter(({ type }) => type === 'script') + .map( + ({ file }) => ``, + ) + .join('') diff --git a/packages/bundler-rspack/src/build/renderPageStyles.ts b/packages/bundler-rspack/src/build/renderPageStyles.ts new file mode 100644 index 0000000000..d97ac87b16 --- /dev/null +++ b/packages/bundler-rspack/src/build/renderPageStyles.ts @@ -0,0 +1,24 @@ +import type { App } from '@vuepress/core' + +import type { FileMeta } from './types.js' + +/** + * Render styles of current page + */ +export const renderPageStyles = ({ + app, + initialFilesMeta, + pageClientFilesMeta, +}: { + app: App + initialFilesMeta: FileMeta[] + pageClientFilesMeta: FileMeta[] +}): string => + // include initial CSS files and other async CSS files of current page + // notice here we put async CSS files after initial CSS files + [...initialFilesMeta, ...pageClientFilesMeta] + .filter(({ type }) => type === 'style') + .map( + ({ file }) => ``, + ) + .join('') diff --git a/packages/bundler-rspack/src/build/resolveClientManifestMeta.ts b/packages/bundler-rspack/src/build/resolveClientManifestMeta.ts new file mode 100644 index 0000000000..8cef9fdb27 --- /dev/null +++ b/packages/bundler-rspack/src/build/resolveClientManifestMeta.ts @@ -0,0 +1,46 @@ +import { resolveFileMeta } from './resolveFileMeta.js' +import type { ClientManifest, FileMeta, ModuleFilesMetaMap } from './types.js' + +/** + * Resolve files meta from clientManifest + */ +export const resolveClientManifestMeta = ({ + all, + initial, + async, + modules, +}: ClientManifest): { + allFilesMeta: FileMeta[] + initialFilesMeta: FileMeta[] + asyncFilesMeta: FileMeta[] + moduleFilesMetaMap: ModuleFilesMetaMap +} => { + // all files meta + const allFilesMeta = all.map(resolveFileMeta) + + // initial files meta + const initialFilesMeta = initial.map(resolveFileMeta) + + // async files meta + const asyncFilesMeta = async.map(resolveFileMeta) + + // module to files meta map + const moduleFilesMetaMap = Object.fromEntries( + Object.entries(modules).map(([moduleRequest, assetFilesIndex]) => [ + moduleRequest, + assetFilesIndex + .map((fileIndex) => allFilesMeta[fileIndex]) + .filter( + ({ file, type }) => + async.includes(file) || (type !== 'style' && type !== 'script'), + ), + ]), + ) + + return { + allFilesMeta, + initialFilesMeta, + asyncFilesMeta, + moduleFilesMetaMap, + } +} diff --git a/packages/bundler-rspack/src/build/resolveFileMeta.ts b/packages/bundler-rspack/src/build/resolveFileMeta.ts new file mode 100644 index 0000000000..f28d0db986 --- /dev/null +++ b/packages/bundler-rspack/src/build/resolveFileMeta.ts @@ -0,0 +1,16 @@ +import { path } from '@vuepress/utils' + +import { resolveFileMetaType } from './resolveFileMetaType.js' +import type { FileMeta } from './types.js' + +/** + * Resolve client file meta from to file name + */ +export const resolveFileMeta = (file: string): FileMeta => { + const extension = path.extname(file).slice(1) + return { + file, + extension, + type: resolveFileMetaType(extension), + } +} diff --git a/packages/bundler-rspack/src/build/resolveFileMetaType.ts b/packages/bundler-rspack/src/build/resolveFileMetaType.ts new file mode 100644 index 0000000000..c19fb4245d --- /dev/null +++ b/packages/bundler-rspack/src/build/resolveFileMetaType.ts @@ -0,0 +1,21 @@ +import type { FileMetaType } from './types.js' + +/** + * Resolve client file type by extension + */ +export const resolveFileMetaType = (extension: string): FileMetaType => { + if (extension === 'js') { + return 'script' + } + if (extension === 'css') { + return 'style' + } + if (/jpe?g|png|svg|gif|webp|ico/i.test(extension)) { + return 'image' + } + if (/woff2?|ttf|otf|eot/i.test(extension)) { + return 'font' + } + // not exhausting all possibilities here, but above covers common cases + return '' +} diff --git a/packages/bundler-rspack/src/build/resolvePageClientFilesMeta.ts b/packages/bundler-rspack/src/build/resolvePageClientFilesMeta.ts new file mode 100644 index 0000000000..17a3c57963 --- /dev/null +++ b/packages/bundler-rspack/src/build/resolvePageClientFilesMeta.ts @@ -0,0 +1,19 @@ +import type { FileMeta, ModuleFilesMetaMap } from './types.js' + +/** + * Get all client files according to module requests of a page + */ +export const resolvePageClientFilesMeta = ({ + moduleRequests, + moduleFilesMetaMap, +}: { + moduleRequests: string[] + moduleFilesMetaMap: ModuleFilesMetaMap +}): FileMeta[] => { + const files = new Set() + moduleRequests.forEach((request) => { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- unsafe indexed access + moduleFilesMetaMap[request]?.forEach((file) => files.add(file)) + }) + return Array.from(files) +} diff --git a/packages/bundler-rspack/src/build/types.ts b/packages/bundler-rspack/src/build/types.ts new file mode 100644 index 0000000000..5eaf515096 --- /dev/null +++ b/packages/bundler-rspack/src/build/types.ts @@ -0,0 +1,39 @@ +/** + * Client file meta + */ +export interface FileMeta { + /** + * file name + */ + file: string + + /** + * file extension + */ + extension: string + + /** + * file type + */ + type: FileMetaType +} + +/** + * Client file meta type, mainly used for + */ +export type FileMetaType = '' | 'font' | 'image' | 'script' | 'style' + +/** + * A "module request" to "client files meta" key-value map + */ +export type ModuleFilesMetaMap = Record + +/** + * Client manifest that collected from webpack stats + */ +export interface ClientManifest { + all: string[] + initial: string[] + async: string[] + modules: Record +} diff --git a/packages/bundler-rspack/src/config/createBaseConfig.ts b/packages/bundler-rspack/src/config/createBaseConfig.ts new file mode 100644 index 0000000000..48476ca747 --- /dev/null +++ b/packages/bundler-rspack/src/config/createBaseConfig.ts @@ -0,0 +1,69 @@ +import type { App } from '@vuepress/core' +import { RspackChain } from 'rspack-chain' + +import type { RspackBundlerOptions } from '../types.js' +import { handleDevtool } from './handleDevtool.js' +import { handleEntry } from './handleEntry.js' +import { handleMode } from './handleMode.js' +import { handleModule } from './handleModule.js' +import { handleNode } from './handleNode.js' +import { handleOtherOptions } from './handleOtherOptions.js' +import { handlePluginDefine } from './handlePluginDefine.js' +import { handleResolve } from './handleResolve.js' + +export const createBaseConfig = async ({ + app, + options, + isBuild, + isServer, +}: { + app: App + options: RspackBundlerOptions + isBuild: boolean + isServer: boolean +}): Promise => { + // create new rspack-chain config + const config = new RspackChain() + + /** + * entry + */ + handleEntry({ app, config }) + + /** + * mode + */ + handleMode({ app, config, isBuild }) + + /** + * node + */ + handleNode({ config }) + + /** + * devtool + */ + handleDevtool({ app, config, isBuild }) + + /** + * resolve + */ + await handleResolve({ app, config, isServer }) + + /** + * module + */ + handleModule({ app, options, config, isBuild, isServer }) + + /** + * plugins + */ + await handlePluginDefine({ app, config, isBuild, isServer }) + + /** + * other options + */ + handleOtherOptions({ app, config, isBuild, isServer }) + + return config +} diff --git a/packages/bundler-rspack/src/config/createClientBaseConfig.ts b/packages/bundler-rspack/src/config/createClientBaseConfig.ts new file mode 100644 index 0000000000..b6259513eb --- /dev/null +++ b/packages/bundler-rspack/src/config/createClientBaseConfig.ts @@ -0,0 +1,32 @@ +import type { App } from '@vuepress/core' +import type { RspackChain } from 'rspack-chain' + +import type { RspackBundlerOptions } from '../types.js' +import { createBaseConfig } from './createBaseConfig.js' + +export const createClientBaseConfig = async ({ + app, + options, + isBuild, +}: { + app: App + options: RspackBundlerOptions + isBuild: boolean +}): Promise => { + const config = await createBaseConfig({ + app, + options, + isServer: false, + isBuild, + }) + + // client output + config.output + .path(app.dir.dest()) + .filename( + isBuild ? 'assets/js/[name].[chunkhash:8].js' : 'assets/js/[name].js', + ) + .publicPath(app.options.base) + + return config +} diff --git a/packages/bundler-rspack/src/config/handleDevtool.ts b/packages/bundler-rspack/src/config/handleDevtool.ts new file mode 100644 index 0000000000..cba5dfe73e --- /dev/null +++ b/packages/bundler-rspack/src/config/handleDevtool.ts @@ -0,0 +1,23 @@ +import type { App } from '@vuepress/core' +import type { RspackChain } from 'rspack-chain' + +/** + * Set webpack devtool + */ +export const handleDevtool = ({ + app, + config, + isBuild, +}: { + app: App + config: RspackChain + isBuild: boolean +}): void => { + if (app.env.isDebug) { + // always enable source-map in debug mode + config.devtool('source-map') + } else if (!isBuild) { + // only enable eval-source-map in dev mode + config.devtool('eval-cheap-module-source-map') + } +} diff --git a/packages/bundler-rspack/src/config/handleEntry.ts b/packages/bundler-rspack/src/config/handleEntry.ts new file mode 100644 index 0000000000..e41b5cf5de --- /dev/null +++ b/packages/bundler-rspack/src/config/handleEntry.ts @@ -0,0 +1,25 @@ +import type { App } from '@vuepress/core' +import { fs } from '@vuepress/utils' +import type { RspackChain } from 'rspack-chain' + +/** + * Set rspack entry + */ +export const handleEntry = ({ + app, + config, +}: { + app: App + config: RspackChain +}): void => { + // set client app as entry point + config.entry('app').add( + app.dir.client( + ( + fs.readJsonSync(app.dir.client('package.json')) as { + exports: { './app': string } + } + ).exports['./app'], + ), + ) +} diff --git a/packages/bundler-rspack/src/config/handleMode.ts b/packages/bundler-rspack/src/config/handleMode.ts new file mode 100644 index 0000000000..6437d150bd --- /dev/null +++ b/packages/bundler-rspack/src/config/handleMode.ts @@ -0,0 +1,17 @@ +import type { App } from '@vuepress/core' +import type { RspackChain } from 'rspack-chain' + +/** + * Set rspack mode + */ +export const handleMode = ({ + app, + config, + isBuild, +}: { + app: App + config: RspackChain + isBuild: boolean +}): void => { + config.mode(!isBuild || app.env.isDebug ? 'development' : 'production') +} diff --git a/packages/bundler-rspack/src/config/handleModule.ts b/packages/bundler-rspack/src/config/handleModule.ts new file mode 100644 index 0000000000..d5fb28689d --- /dev/null +++ b/packages/bundler-rspack/src/config/handleModule.ts @@ -0,0 +1,48 @@ +import type { App } from '@vuepress/core' +import type { RspackChain } from 'rspack-chain' + +import type { RspackBundlerOptions } from '../types.js' +import { handleModuleAssets } from './handleModuleAssets.js' +import { handleModuleJs } from './handleModuleJs.js' +import { handleModulePug } from './handleModulePug.js' +import { handleModuleStyles } from './handleModuleStyles.js' +import { handleModuleTs } from './handleModuleTs.js' +import { handleModuleVue } from './handleModuleVue.js' + +/** + * Set rspack module + */ +export const handleModule = ({ + app, + options, + config, + isBuild, + isServer, +}: { + app: App + options: RspackBundlerOptions + config: RspackChain + isBuild: boolean + isServer: boolean +}): void => { + // noParse + config.module.noParse(/(^(vue|vue-router)$)|(^@vue\/[^/]*$)/) + + // vue files + handleModuleVue({ app, options, config, isBuild, isServer }) + + // pug files, for templates + handleModulePug({ config }) + + // images & media & fonts + handleModuleAssets({ config }) + + // js files + handleModuleJs({ options, config, isBuild, isServer }) + + // ts files + handleModuleTs({ config }) + + // styles files + handleModuleStyles({ options, config, isBuild, isServer }) +} diff --git a/packages/bundler-rspack/src/config/handleModuleAssets.ts b/packages/bundler-rspack/src/config/handleModuleAssets.ts new file mode 100644 index 0000000000..fe53170a09 --- /dev/null +++ b/packages/bundler-rspack/src/config/handleModuleAssets.ts @@ -0,0 +1,48 @@ +import type { RspackChain } from 'rspack-chain' + +/** + * Set webpack config to handle assets files + */ +export const handleModuleAssets = ({ + config, +}: { + config: RspackChain +}): void => { + // images + config.module + .rule('images') + .test(/\.(png|jpe?g|gif|webp)(\?.*)?$/i) + .type('asset') + .generator({ + filename: 'assets/img/[name].[contenthash:8][ext]', + }) + + // svg + // do not base64-inline SVGs. + // https://github.com/facebookincubator/create-react-app/pull/1180 + config.module + .rule('svg') + .test(/\.(svg)(\?.*)?$/i) + .type('asset/resource') + .generator({ + filename: 'assets/img/[name].[contenthash:8][ext]', + }) + + // media + config.module + .rule('media') + .test(/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/i) + .type('asset/resource') + .generator({ + filename: 'assets/media/[name].[contenthash:8][ext]', + }) + + // fonts + config.module + .rule('fonts') + .test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/i) + .type('asset/resource') + .generator({ + filename: 'assets/fonts/[name].[contenthash:8][ext]', + }) +} diff --git a/packages/bundler-rspack/src/config/handleModuleJs.ts b/packages/bundler-rspack/src/config/handleModuleJs.ts new file mode 100644 index 0000000000..41a41f5f1d --- /dev/null +++ b/packages/bundler-rspack/src/config/handleModuleJs.ts @@ -0,0 +1,58 @@ +import { createRequire } from 'node:module' + +import type { RspackChain } from 'rspack-chain' + +import type { RspackBundlerOptions } from '../types.js' +import { resolveEsbuildLoaderOptions } from './resolveEsbuildLoaderOptions.js' + +const require = createRequire(import.meta.url) + +/** + * Set webpack module to handle js files + */ +export const handleModuleJs = ({ + options, + config, + isBuild, + isServer, +}: { + options: RspackBundlerOptions + config: RspackChain + isBuild: boolean + isServer: boolean +}): void => { + // only enable transpilation in production client bundle + // when `evergreen` option is set to `false` + if (options.evergreen !== false || !isBuild || isServer) { + return + } + + config.module + .rule('js') + .test(/\.jsx?$/) + .exclude.add((filePath) => { + // always transpile js / jsx in vue files + if (/\.vue\.jsx?$/.test(filePath)) { + return false + } + // transpile all core packages and vuepress related packages. + // i.e. + // @vuepress/* + // vuepress-* + if ( + /(@vuepress[/\\][^/\\]*|vuepress-[^/\\]*)[/\\](?!node_modules).*\.js$/.test( + filePath, + ) + ) { + return false + } + // don't transpile node_modules + return filePath.includes('node_modules') + }) + .end() + // use esbuild-loader + .use('esbuild-loader') + .loader(require.resolve('esbuild-loader')) + .options(resolveEsbuildLoaderOptions()) + .end() +} diff --git a/packages/bundler-rspack/src/config/handleModulePug.ts b/packages/bundler-rspack/src/config/handleModulePug.ts new file mode 100644 index 0000000000..ce937d0944 --- /dev/null +++ b/packages/bundler-rspack/src/config/handleModulePug.ts @@ -0,0 +1,12 @@ +import type { RspackChain } from 'rspack-chain' + +/** + * Set webpack module to handle pug files + */ +export const handleModulePug = ({ config }: { config: RspackChain }): void => { + config.module + .rule('pug') + .test(/\.pug$/) + .use('pug-plain-loader') + .loader('pug-plain-loader') +} diff --git a/packages/bundler-rspack/src/config/handleModuleStyles.ts b/packages/bundler-rspack/src/config/handleModuleStyles.ts new file mode 100644 index 0000000000..63f000272a --- /dev/null +++ b/packages/bundler-rspack/src/config/handleModuleStyles.ts @@ -0,0 +1,130 @@ +import { createRequire } from 'node:module' + +import { CssExtractRspackPlugin } from '@rspack/core' +import autoprefixer from 'autoprefixer' +import type { RspackChain } from 'rspack-chain' + +import type { + RspackBundlerOptions, + StylePreprocessorLoaderOptions, +} from '../types.js' + +const require = createRequire(import.meta.url) + +/** + * Set webpack module to handle style files + */ +export const handleModuleStyles = ({ + options, + config, + isBuild, + isServer, +}: { + options: RspackBundlerOptions + config: RspackChain + isBuild: boolean + isServer: boolean +}): void => { + const handleStyle = ({ + lang, + test, + loaderName, + loaderOptions, + }: { + lang: string + test: RegExp + loaderName?: string + loaderOptions?: StylePreprocessorLoaderOptions + }): void => { + const rule = config.module.rule(lang).test(test) + + if (!isServer) { + if (isBuild) { + rule.use('css-extract-loader').loader(CssExtractRspackPlugin.loader) + } else { + rule.use('style-loader').loader(require.resolve('style-loader')) + } + } + + // use css-loader + rule + .use('css-loader') + .loader(require.resolve('css-loader')) + .options({ + modules: { + auto: true, + exportLocalsConvention: 'as-is', + exportOnlyLocals: isServer, + localIdentName: `[local]_[contenthash:base64:8]`, + namedExport: false, + }, + importLoaders: loaderName ? 2 : 1, + }) + + // use postcss-loader + rule + .use('postcss-loader') + .loader(require.resolve('postcss-loader')) + .options({ + postcssOptions: { + plugins: [autoprefixer], + }, + ...options.postcss, + }) + + // use extra loader + if (loaderName) { + rule + .use(loaderName) + .loader(loaderName) + .options(loaderOptions ?? {}) + } + } + + handleStyle({ + lang: 'css', + test: /\.css$/, + }) + + handleStyle({ + lang: 'postcss', + test: /\.p(ost)?css$/, + }) + + handleStyle({ + lang: 'scss', + test: /\.scss$/, + loaderName: 'sass-loader', + loaderOptions: options.scss, + }) + + handleStyle({ + lang: 'sass', + test: /\.sass$/, + loaderName: 'sass-loader', + loaderOptions: options.sass, + }) + + handleStyle({ + lang: 'less', + test: /\.less$/, + loaderName: 'less-loader', + loaderOptions: options.less, + }) + + handleStyle({ + lang: 'stylus', + test: /\.styl(us)?$/, + loaderName: 'stylus-loader', + loaderOptions: { + stylusOptions: { + // allow literal css import + includeCSS: true, + // no need to compress with stylus + // we will handle it by postcss-loader + compress: false, + }, + ...options.stylus, + }, + }) +} diff --git a/packages/bundler-rspack/src/config/handleModuleTs.ts b/packages/bundler-rspack/src/config/handleModuleTs.ts new file mode 100644 index 0000000000..03b7baa21e --- /dev/null +++ b/packages/bundler-rspack/src/config/handleModuleTs.ts @@ -0,0 +1,25 @@ +import { createRequire } from 'node:module' + +import type { RspackChain } from 'rspack-chain' + +import { resolveEsbuildLoaderOptions } from './resolveEsbuildLoaderOptions.js' + +const require = createRequire(import.meta.url) + +/** + * Set webpack module to handle ts files + */ +export const handleModuleTs = ({ config }: { config: RspackChain }): void => { + config.module + .rule('ts') + .test(/\.tsx?/) + // use esbuild-loader + .use('esbuild-loader') + .loader(require.resolve('esbuild-loader')) + .options( + resolveEsbuildLoaderOptions({ + loader: 'tsx', + }), + ) + .end() +} diff --git a/packages/bundler-rspack/src/config/handleModuleVue.ts b/packages/bundler-rspack/src/config/handleModuleVue.ts new file mode 100644 index 0000000000..11296ef7bb --- /dev/null +++ b/packages/bundler-rspack/src/config/handleModuleVue.ts @@ -0,0 +1,71 @@ +import { createRequire } from 'node:module' + +import type { App } from '@vuepress/core' +import type { RspackChain } from 'rspack-chain' +import type { VueLoaderOptions } from 'vue-loader' +import { VueLoaderPlugin } from 'vue-loader' + +import type { VuepressMarkdownLoaderOptions } from '../loaders/vuepressMarkdownLoader' +import type { RspackBundlerOptions } from '../types.js' + +const require = createRequire(import.meta.url) + +/** + * Set webpack module to handle vue files + */ +export const handleModuleVue = ({ + app, + options, + config, + isBuild, + isServer, +}: { + app: App + options: RspackBundlerOptions + config: RspackChain + isBuild: boolean + isServer: boolean +}): void => { + const handleVue = ({ + lang, + test, + }: { + lang: 'md' | 'vue' + test: RegExp + }): void => { + const rule = config.module.rule(lang).test(test) + + // use internal vuepress-ssr-loader to handle SSR dependencies + if (isBuild) { + rule + .use('vuepress-ssr-loader') + .loader(require.resolve('#vuepress-ssr-loader')) + .end() + } + + // use official vue-loader + rule + .use('vue-loader') + .loader(require.resolve('vue-loader')) + .options({ + ...options.vue, + isServerBuild: isServer, + } satisfies VueLoaderOptions) + .end() + + // use internal vuepress-markdown-loader to handle markdown files + if (lang === 'md') { + rule + .use('vuepress-markdown-loader') + .loader(require.resolve('#vuepress-markdown-loader')) + .options({ app } satisfies VuepressMarkdownLoaderOptions) + .end() + } + } + + handleVue({ lang: 'md', test: /\.md$/ }) + handleVue({ lang: 'vue', test: /\.vue$/ }) + + // use vue-loader plugin + config.plugin('vue-loader').use(VueLoaderPlugin) +} diff --git a/packages/bundler-rspack/src/config/handleNode.ts b/packages/bundler-rspack/src/config/handleNode.ts new file mode 100644 index 0000000000..ca28423052 --- /dev/null +++ b/packages/bundler-rspack/src/config/handleNode.ts @@ -0,0 +1,12 @@ +import type { RspackChain } from 'rspack-chain' + +/** + * Set webpack node config + */ +export const handleNode = ({ config }: { config: RspackChain }): void => { + // do not polyfill or mock node globals and modules + config.node + .set('__filename', false) + .set('__dirname', false) + .set('global', false) +} diff --git a/packages/bundler-rspack/src/config/handleOtherOptions.ts b/packages/bundler-rspack/src/config/handleOtherOptions.ts new file mode 100644 index 0000000000..179f633f04 --- /dev/null +++ b/packages/bundler-rspack/src/config/handleOtherOptions.ts @@ -0,0 +1,51 @@ +import { createRequire } from 'node:module' + +import type { App } from '@vuepress/core' +import type { RspackChain } from 'rspack-chain' + +const require = createRequire(import.meta.url) + +/** + * Set rspack other options + * + * @see https://rspack.rs/config/other-options + */ +export const handleOtherOptions = ({ + app, + config, + isBuild, + isServer, +}: { + app: App + config: RspackChain + isBuild: boolean + isServer: boolean +}): void => { + // set infrastructureLogging options + config.infrastructureLogging({ + level: app.env.isDebug ? 'info' : 'error', + }) + + // set cache options + config.cache({ + type: 'persistent', + storage: { + type: 'filesystem', + directory: app.dir.cache(), + }, + version: JSON.stringify({ + // vuepress identifiers + isBuild, + isServer, + 'version': app.version, + // dependencies + 'esbuild-loader': ( + require('esbuild-loader/package.json') as { version: string } + ).version, + 'vue-loader': (require('vue-loader/package.json') as { version: string }) + .version, + 'webpack': (require('webpack/package.json') as { version: string }) + .version, + }), + }) +} diff --git a/packages/bundler-rspack/src/config/handlePluginDefine.ts b/packages/bundler-rspack/src/config/handlePluginDefine.ts new file mode 100644 index 0000000000..d2de6c9246 --- /dev/null +++ b/packages/bundler-rspack/src/config/handlePluginDefine.ts @@ -0,0 +1,49 @@ +import { DefinePlugin } from '@rspack/core' +import type { App } from '@vuepress/core' +import type { RspackChain } from 'rspack-chain' + +/** + * Set rspack DefinePlugin + */ +export const handlePluginDefine = async ({ + app, + config, + isBuild, + isServer, +}: { + app: App + config: RspackChain + isBuild: boolean + isServer: boolean +}): Promise => { + // define plugin + config.plugin('define').use(DefinePlugin, [ + { + __VUEPRESS_VERSION__: JSON.stringify(app.version), + __VUEPRESS_BASE__: JSON.stringify(app.options.base), + __VUEPRESS_DEV__: JSON.stringify(!isBuild), + __VUEPRESS_SSR__: JSON.stringify(isServer), + // @see http://link.vuejs.org/feature-flags + // enable options API by default + __VUE_OPTIONS_API__: JSON.stringify(true), + __VUE_PROD_DEVTOOLS__: JSON.stringify(app.env.isDebug), + __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: JSON.stringify(app.env.isDebug), + }, + ]) + + // plugin hook: define + const defineResult = await app.pluginApi.hooks.define.process(app, isServer) + + // tap the arguments of DefinePlugin + config.plugin('define').tap(([options]) => { + defineResult.forEach((defineObject) => { + Object.entries(defineObject).forEach(([key, value]) => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + options[key] = JSON.stringify(value) + }) + }) + + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return [options] + }) +} diff --git a/packages/bundler-rspack/src/config/handleResolve.ts b/packages/bundler-rspack/src/config/handleResolve.ts new file mode 100644 index 0000000000..986ece5320 --- /dev/null +++ b/packages/bundler-rspack/src/config/handleResolve.ts @@ -0,0 +1,53 @@ +import type { App } from '@vuepress/core' +import type { RspackChain } from 'rspack-chain' + +/** + * Set rspack resolve + */ +export const handleResolve = async ({ + app, + config, + isServer, +}: { + app: App + config: RspackChain + isServer: boolean +}): Promise => { + // aliases + const alias = { + '@source': app.dir.source(), + '@temp': app.dir.temp(), + '@internal': app.dir.temp('internal'), + } + + // plugin hook: alias + const aliasResult = await app.pluginApi.hooks.alias.process(app, isServer) + + aliasResult.forEach((aliasObject) => { + Object.assign(alias, aliasObject) + }) + + // set aliases + config.resolve.alias.merge( + Object.fromEntries( + // sort alias by length in descending order to ensure longer alias is handled first + Object.entries(alias).sort(([a], [b]) => b.length - a.length), + ), + ) + + // extensions + config.resolve.extensions.merge([ + '.js', + '.jsx', + '.ts', + '.tsx', + '.vue', + '.json', + ]) + + // extensionAlias + config.resolve.extensionAlias.merge({ + '.js': ['.js', '.ts'], + '.mjs': ['.mjs', '.mts'], + }) +} diff --git a/packages/bundler-rspack/src/config/index.ts b/packages/bundler-rspack/src/config/index.ts new file mode 100644 index 0000000000..0d24bfe05d --- /dev/null +++ b/packages/bundler-rspack/src/config/index.ts @@ -0,0 +1,2 @@ +export * from './createBaseConfig.js' +export * from './createClientBaseConfig.js' diff --git a/packages/bundler-rspack/src/config/resolveEsbuildLoaderOptions.ts b/packages/bundler-rspack/src/config/resolveEsbuildLoaderOptions.ts new file mode 100644 index 0000000000..21ea899db0 --- /dev/null +++ b/packages/bundler-rspack/src/config/resolveEsbuildLoaderOptions.ts @@ -0,0 +1,23 @@ +import type { EsbuildPluginOptions } from 'esbuild-loader' + +export const resolveEsbuildLoaderOptions = ( + options: EsbuildPluginOptions = {}, +): EsbuildPluginOptions => ({ + /** + * keep consistent with vite + * + * @see https://vite.dev/config/build-options.html#build-target + */ + target: ['es2023', 'chrome111', 'edge111', 'firefox114', 'safari16.4'], + + /** + * jsx options + */ + jsxFactory: 'jsx', + jsxFragment: 'Fragment', + + /** + * overrides + */ + ...options, +}) diff --git a/packages/bundler-rspack/src/dev/createDevConfig.ts b/packages/bundler-rspack/src/dev/createDevConfig.ts new file mode 100644 index 0000000000..e93c75b60a --- /dev/null +++ b/packages/bundler-rspack/src/dev/createDevConfig.ts @@ -0,0 +1,28 @@ +import type { App } from '@vuepress/core' +import HtmlPlugin from 'html-webpack-plugin' +import webpack from 'webpack' +import type { Config } from 'webpack-v5-chain' + +import { createClientBaseConfig } from '../config/index.js' +import type { RspackBundlerOptions } from '../types.js' + +export const createDevConfig = async ( + app: App, + options: RspackBundlerOptions, +): Promise => { + const config = await createClientBaseConfig({ + app, + options, + isBuild: false, + }) + + config.plugin('html').use(HtmlPlugin, [ + { + template: app.options.templateDev, + }, + ]) + + config.plugin('hmr').use(webpack.HotModuleReplacementPlugin) + + return config +} diff --git a/packages/bundler-rspack/src/dev/createDevServerConfig.ts b/packages/bundler-rspack/src/dev/createDevServerConfig.ts new file mode 100644 index 0000000000..5ed3dd25bb --- /dev/null +++ b/packages/bundler-rspack/src/dev/createDevServerConfig.ts @@ -0,0 +1,50 @@ +import { sep } from 'node:path' + +import type { App } from '@vuepress/core' +import { path } from '@vuepress/utils' +import type WebpackDevServer from 'webpack-dev-server' + +import type { RspackBundlerOptions } from '../types.js' +import { trailingSlashMiddleware } from './trailingSlashMiddleware.js' + +export const createDevServerConfig = ( + app: App, + options: RspackBundlerOptions, +): WebpackDevServer.Configuration => ({ + allowedHosts: 'all', + compress: true, + devMiddleware: { + publicPath: app.options.base, + writeToDisk: false, + stats: app.env.isDebug ? 'normal' : 'errors-warnings', + }, + headers: { + 'access-control-allow-origin': '*', + }, + historyApiFallback: { + disableDotRule: true, + rewrites: [{ from: /./, to: path.join(app.options.base, 'index.html') }], + }, + host: app.options.host, + hot: true, + setupMiddlewares: (middlewares, devServer) => { + devServer.app?.use(trailingSlashMiddleware) + return ( + options.devServerSetupMiddlewares?.(middlewares, devServer) ?? middlewares + ) + }, + open: app.options.open, + port: app.options.port, + static: { + // `static.directory` will fail on Windows if we do not replace / with \ + directory: app.dir.public().replace('/', sep), + publicPath: app.options.base, + watch: { + ignoreInitial: true, + ignored: [ + // Do not watch node_modules + 'node_modules', + ], + }, + }, +}) diff --git a/packages/bundler-rspack/src/dev/dev.ts b/packages/bundler-rspack/src/dev/dev.ts new file mode 100644 index 0000000000..1797f9e950 --- /dev/null +++ b/packages/bundler-rspack/src/dev/dev.ts @@ -0,0 +1,87 @@ +import type { App, Bundler } from '@vuepress/core' +import { colors, logger, ora } from '@vuepress/utils' +import webpack from 'webpack' +import WebpackDevServer from 'webpack-dev-server' + +import { resolveRspackConfig } from '../resolveRspackConfig.js' +import type { RspackBundlerOptions } from '../types.js' +import { createDevConfig } from './createDevConfig.js' +import { createDevServerConfig } from './createDevServerConfig.js' + +/** + * Create the dev method of webpack bundler + */ +export const dev = async ( + options: RspackBundlerOptions, + app: App, +): ReturnType => { + // plugin hook: extendsBundlerOptions + await app.pluginApi.hooks.extendsBundlerOptions.process(options, app) + + // create webpack config + const webpackConfig = resolveRspackConfig({ + config: await createDevConfig(app, options), + options, + isServer: false, + isBuild: false, + }) + + // create webpack compiler + const compiler = webpack(webpackConfig) + + // create webpack-dev-server + const serverConfig = createDevServerConfig(app, options) + const server = new WebpackDevServer(serverConfig, compiler) + + const [, close] = await Promise.all([ + // wait for webpack-dev-server to start + server.start(), + + // wait for webpack compilation to complete + new Promise<() => Promise>((resolve, reject) => { + // create spinner + const spinner = ora() + let hasStarted = false + let hasFinished = false + + // start spinner before the first compilation + compiler.hooks.beforeCompile.tap('vuepress-dev', () => { + if (hasStarted) return + hasStarted = true + + spinner.start('Compiling with webpack...') + }) + + // stop spinner, show compilation time and print url after first compilation + compiler.hooks.done.tap('vuepress-dev', ({ endTime, startTime }) => { + if (hasFinished) return + hasFinished = true + + spinner.succeed(`Compilation finished in ${endTime - startTime}ms`) + + // replace `0.0.0.0` with `localhost` as `0.0.0.0` is not available on windows + const url = `http://${ + serverConfig.host === '0.0.0.0' ? 'localhost' : serverConfig.host + }:${serverConfig.port}${app.options.base}` + logger.success( + `VuePress webpack dev server is listening at ${colors.cyan(url)}`, + ) + + // resolve the close function + resolve(async (): Promise => server.stop()) + }) + + // stop spinner and reject error if the first compilation is failed + compiler.hooks.failed.tap('vuepress-dev', (err) => { + if (hasFinished) return + hasFinished = true + + spinner.fail('Compilation failed') + reject(err) + }) + }), + ]) + + // return the close function + return close +} diff --git a/packages/bundler-rspack/src/dev/index.ts b/packages/bundler-rspack/src/dev/index.ts new file mode 100644 index 0000000000..b55b120468 --- /dev/null +++ b/packages/bundler-rspack/src/dev/index.ts @@ -0,0 +1 @@ +export * from './dev.js' diff --git a/packages/bundler-rspack/src/dev/trailingSlashMiddleware.ts b/packages/bundler-rspack/src/dev/trailingSlashMiddleware.ts new file mode 100644 index 0000000000..34d34e0717 --- /dev/null +++ b/packages/bundler-rspack/src/dev/trailingSlashMiddleware.ts @@ -0,0 +1,26 @@ +import type { RequestHandler } from 'express' + +/** + * A middleware to add trailing slash to the url + * + * It will redirect '/foo' to '/foo/' with 302 + */ +export const trailingSlashMiddleware: RequestHandler = (req, res, next) => { + if ( + // only add trailing slash in GET and HEAD requests + !['GET', 'HEAD'].includes(req.method) || + // if the last section of the path has a dot, we think it has extension + // and should not add trailing slash + req.path.split('/').pop()?.includes('.') || + // if the path already has trailing slash + req.path.endsWith('/') + ) { + next() + return + } + + // add trailing slash and retain query + // notice that we should not use 301 in dev-server + const query = req.url.slice(req.path.length) + res.redirect(302, `${req.path}/${query}`) +} diff --git a/packages/bundler-rspack/src/index.ts b/packages/bundler-rspack/src/index.ts new file mode 100644 index 0000000000..dfe07538ae --- /dev/null +++ b/packages/bundler-rspack/src/index.ts @@ -0,0 +1,5 @@ +import { rspackBundler } from './rspackBundler.js' + +export type * from './types.js' +export * from './rspackBundler.js' +export default rspackBundler diff --git a/packages/bundler-rspack/src/loaders/vuepressMarkdownLoader.cts b/packages/bundler-rspack/src/loaders/vuepressMarkdownLoader.cts new file mode 100644 index 0000000000..f4b3001431 --- /dev/null +++ b/packages/bundler-rspack/src/loaders/vuepressMarkdownLoader.cts @@ -0,0 +1,3 @@ +const loader = require('./vuepressMarkdownLoader.js') + +module.exports = loader.vuepressMarkdownLoader diff --git a/packages/bundler-rspack/src/loaders/vuepressMarkdownLoader.ts b/packages/bundler-rspack/src/loaders/vuepressMarkdownLoader.ts new file mode 100644 index 0000000000..0b9251468a --- /dev/null +++ b/packages/bundler-rspack/src/loaders/vuepressMarkdownLoader.ts @@ -0,0 +1,39 @@ +import type { App } from '@vuepress/core' +import type { LoaderDefinitionFunction } from 'webpack' + +export interface VuepressMarkdownLoaderOptions { + app: App +} + +/** + * A webpack loader to transform markdown content to vue component + */ +export const vuepressMarkdownLoader: LoaderDefinitionFunction = + async function vuepressMarkdownLoader(source) { + // import esm dependencies + const [{ createPage, renderPageToVue }, { path }] = await Promise.all([ + import('@vuepress/core'), + import('@vuepress/utils'), + ]) + + // get app instance from loader options + const { app } = this.getOptions() + + // normalize the resource path to use forward slashes on Windows + const filePath = path.normalize(this.resourcePath) + + // get the matched page by file path + const page = app.pagesMap[filePath] + + // if the page content is not changed, render it to vue component directly + if (page?.content === source) { + return renderPageToVue(app, page) + } + + // create a new page with the new content + const newPage = await createPage(app, { + content: source, + filePath, + }) + return renderPageToVue(app, newPage) + } diff --git a/packages/bundler-rspack/src/loaders/vuepressSsrLoader.cts b/packages/bundler-rspack/src/loaders/vuepressSsrLoader.cts new file mode 100644 index 0000000000..91a7941ebb --- /dev/null +++ b/packages/bundler-rspack/src/loaders/vuepressSsrLoader.cts @@ -0,0 +1,3 @@ +const { vuepressSsrLoader } = require('./vuepressSsrLoader.js') + +module.exports = vuepressSsrLoader diff --git a/packages/bundler-rspack/src/loaders/vuepressSsrLoader.ts b/packages/bundler-rspack/src/loaders/vuepressSsrLoader.ts new file mode 100644 index 0000000000..65ac64e175 --- /dev/null +++ b/packages/bundler-rspack/src/loaders/vuepressSsrLoader.ts @@ -0,0 +1,29 @@ +import type { LoaderDefinitionFunction } from 'webpack' + +/** + * A webpack loader to handle SSR dependencies + * + * This loader will only take effect in server bundle + * because we only replace `ssrRender` code + * + * But we still need to use this loader in client, + * to ensure that the module `request` in client and + * server bundle are the same + */ +export const vuepressSsrLoader: LoaderDefinitionFunction = + function vuepressSsrLoader(source) { + // add `request` to `ssrContext._registeredComponents` to handle SSR dependencies + // notice that this could only handle those sfc that cannot use inline template + // see https://github.com/vuejs/vue-loader/blob/1b1a195612f885a8dec3f371edf1cb8b35d341e4/src/index.ts#L167-L183 + return source.replace( + /import { ssrRender } from (.*)\n/, + `import { ssrRender as _ssrRender } from $1 +import { ssrContextKey } from 'vue' +const ssrRender = (...args) => { + const ssrContext = args[2].appContext.provides[ssrContextKey] + ssrContext._registeredComponents.add(${JSON.stringify(this.request)}) + return _ssrRender(...args) +} +`, + ) + } diff --git a/packages/bundler-rspack/src/resolveRspackConfig.ts b/packages/bundler-rspack/src/resolveRspackConfig.ts new file mode 100644 index 0000000000..500e3e92d8 --- /dev/null +++ b/packages/bundler-rspack/src/resolveRspackConfig.ts @@ -0,0 +1,38 @@ +import type { Configuration } from '@rspack/core' +import type { RspackChain } from 'rspack-chain' +import { merge } from 'rspack-merge' + +import type { RspackBundlerOptions } from './types.js' + +export const resolveRspackConfig = ({ + config, + options, + isServer, + isBuild, +}: { + config: RspackChain + options: RspackBundlerOptions + isServer: boolean + isBuild: boolean +}): Configuration => { + // allow modifying rspack config via `chainRspack` + options.chainRspack?.(config, isServer, isBuild) + + // generate rspack config from rspack-chain + const rspackConfig = config.toConfig() + + // allow modifying rspack config via `configureRspack` + const configureRspackResult = options.configureRspack?.( + rspackConfig, + isServer, + isBuild, + ) + + // if `configureRspack` returns a configuration object, + // use rspack-merge to merge it + if (configureRspackResult) { + return merge(rspackConfig, configureRspackResult) + } + + return rspackConfig +} diff --git a/packages/bundler-rspack/src/rspackBundler.ts b/packages/bundler-rspack/src/rspackBundler.ts new file mode 100644 index 0000000000..bb05b2ba22 --- /dev/null +++ b/packages/bundler-rspack/src/rspackBundler.ts @@ -0,0 +1,11 @@ +import type { Bundler } from '@vuepress/core' + +import { build } from './build/index.js' +import { dev } from './dev/index.js' +import type { RspackBundlerOptions } from './types.js' + +export const rspackBundler = (options: RspackBundlerOptions = {}): Bundler => ({ + name: '@vuepress/bundler-rspack', + dev: async (app) => dev(options, app), + build: async (app) => build(options, app), +}) diff --git a/packages/bundler-rspack/src/types.ts b/packages/bundler-rspack/src/types.ts new file mode 100644 index 0000000000..32338014ad --- /dev/null +++ b/packages/bundler-rspack/src/types.ts @@ -0,0 +1,144 @@ +import type { + LoaderContext, + Configuration as RspackConfiguration, +} from '@rspack/core' +import type { + RspackDevServer, + Configuration as RspackDevServerConfiguration, +} from '@rspack/dev-server' +import type { BundlerOptions } from '@vuepress/core' +import type { RspackChain } from 'rspack-chain' +import type { VueLoaderOptions } from 'vue-loader' + +export type { VueLoaderOptions, RspackConfiguration, RspackDevServer } + +/** + * Options for bundler-rspack + */ +export interface RspackBundlerOptions extends BundlerOptions { + /** + * use rspack-merge to set rspack config + */ + configureRspack?: ( + config: RspackConfiguration, + isServer: boolean, + isBuild: boolean, + ) => RspackConfiguration | void + + /** + * use rspack-chain to set rspack config + */ + chainRspack?: ( + config: RspackChain, + isServer: boolean, + isBuild: boolean, + ) => void + + /** + * `setupMiddlewares` config of rspack-dev-server + */ + devServerSetupMiddlewares?: RspackDevServerConfiguration['setupMiddlewares'] + + /** + * vue-loader options + */ + vue?: VueLoaderOptions + + /** + * postcss-loader options + */ + postcss?: PostcssLoaderOptions + + /** + * stylus-loader options + */ + stylus?: StylusLoaderOptions + + /** + * sass-loader options for scss files + */ + scss?: SassLoaderOptions + + /** + * sass-loader options for sass files + */ + sass?: SassLoaderOptions + + /** + * less-loader options + */ + less?: LessLoaderOptions + + /** + * only target evergreen browsers or not + */ + evergreen?: boolean +} + +/** + * Common options for style preprocessor webpack loaders + */ +export interface StylePreprocessorLoaderOptions { + additionalData?: + | string + | (( + content: string, + loaderContext: LoaderContext>, + ) => string) + sourceMap?: boolean + webpackImporter?: boolean +} + +/** + * Common type for style pre-processor options + */ +export type StylePreprocessorOptions< + T extends Record = Record, +> = T | ((loaderContext: LoaderContext) => TextDecodeOptions) + +/** + * Options for postcss-loader + * + * @see https://github.com/webpack-contrib/postcss-loader#options + */ +export interface PostcssLoaderOptions extends Pick< + StylePreprocessorLoaderOptions, + 'sourceMap' +> { + execute?: boolean + implementation?: string | ((...args: unknown[]) => unknown) + postcssOptions?: StylePreprocessorOptions +} + +/** + * Options for stylus-loader + * + * @see https://github.com/webpack-contrib/stylus-loader#options + */ +export interface StylusLoaderOptions extends StylePreprocessorLoaderOptions { + implementation?: string | ((...args: unknown[]) => unknown) + stylusOptions?: StylePreprocessorOptions +} + +/** + * Options for sass-loader + * + * @see https://github.com/webpack-contrib/sass-loader#options + */ +export interface SassLoaderOptions extends StylePreprocessorLoaderOptions { + api?: 'legacy' | 'modern-compiler' | 'modern' + implementation?: Record | string + sassOptions?: StylePreprocessorOptions + warnRuleAsWarning?: boolean +} + +/** + * Options for less-loader + * + * @see https://github.com/webpack-contrib/less-loader#options + */ +export interface LessLoaderOptions extends StylePreprocessorLoaderOptions { + implementation?: Record | string + lessLogAsWarnOrErr?: boolean + lessOptions?: StylePreprocessorOptions +} diff --git a/packages/bundler-rspack/tsdown.config.ts b/packages/bundler-rspack/tsdown.config.ts new file mode 100644 index 0000000000..5faba7d5a0 --- /dev/null +++ b/packages/bundler-rspack/tsdown.config.ts @@ -0,0 +1,25 @@ +import { defineConfig } from 'tsdown' + +const shared = defineConfig({ + fixedExtension: false, + target: 'es2023', + tsconfig: '../tsconfig.dts.json', +}) + +export default defineConfig([ + { + ...shared, + dts: true, + entry: './src/index.ts', + format: 'esm', + }, + { + ...shared, + dts: false, + entry: { + 'vuepress-markdown-loader': './src/loaders/vuepressMarkdownLoader.cts', + 'vuepress-ssr-loader': './src/loaders/vuepressSsrLoader.cts', + }, + format: 'cjs', + }, +]) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b724b5ab36..9b69cb0e11 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -128,7 +128,7 @@ importers: version: 1.99.0 sass-loader: specifier: ^16.0.7 - version: 16.0.7(sass-embedded@1.99.0)(sass@1.99.0)(webpack@5.106.2(esbuild@0.28.0)) + version: 16.0.7(@rspack/core@2.0.3)(sass-embedded@1.99.0)(sass@1.99.0)(webpack@5.106.2(esbuild@0.28.0)) vue: specifier: catalog:vue version: 3.5.34(typescript@6.0.3) @@ -146,6 +146,72 @@ importers: specifier: ^14.2.6 version: 14.2.6 + packages/bundler-rspack: + dependencies: + '@rspack/core': + specifier: ^2.0.3 + version: 2.0.3 + '@rspack/dev-server': + specifier: ^2.0.1 + version: 2.0.1(@rspack/core@2.0.3)(selfsigned@5.5.0) + '@types/express': + specifier: ^4.17.25 + version: 4.17.25 + '@vuepress/bundlerutils': + specifier: workspace:* + version: link:../bundlerutils + '@vuepress/client': + specifier: workspace:* + version: link:../client + '@vuepress/core': + specifier: workspace:* + version: link:../core + '@vuepress/shared': + specifier: workspace:* + version: link:../shared + '@vuepress/utils': + specifier: workspace:* + version: link:../utils + autoprefixer: + specifier: ^10.5.0 + version: 10.5.0(postcss@8.5.14) + css-loader: + specifier: ^7.1.4 + version: 7.1.4(@rspack/core@2.0.3)(webpack@5.106.2(esbuild@0.28.0)) + esbuild-loader: + specifier: ~4.4.3 + version: 4.4.3(webpack@5.106.2(esbuild@0.28.0)) + express: + specifier: ^4.22.1 + version: 4.22.1 + html-webpack-plugin: + specifier: ^5.6.7 + version: 5.6.7(@rspack/core@2.0.3)(webpack@5.106.2(esbuild@0.28.0)) + postcss: + specifier: ^8.5.14 + version: 8.5.14 + postcss-loader: + specifier: ^8.2.1 + version: 8.2.1(@rspack/core@2.0.3)(postcss@8.5.14)(typescript@6.0.3)(webpack@5.106.2(esbuild@0.28.0)) + rspack-chain: + specifier: ^2.0.1 + version: 2.0.1(@rspack/core@2.0.3) + rspack-merge: + specifier: ^0.1.1 + version: 0.1.1 + style-loader: + specifier: ^4.0.0 + version: 4.0.0(webpack@5.106.2(esbuild@0.28.0)) + vue: + specifier: catalog:vue + version: 3.5.34(typescript@6.0.3) + vue-loader: + specifier: ^17.4.2 + version: 17.4.2(@vue/compiler-sfc@3.5.34)(vue@3.5.34(typescript@6.0.3))(webpack@5.106.2(esbuild@0.28.0)) + vue-router: + specifier: catalog:vue + version: 5.0.6(@vue/compiler-sfc@3.5.34)(vue@3.5.34(typescript@6.0.3)) + packages/bundler-vite: dependencies: '@vitejs/plugin-vue': @@ -226,7 +292,7 @@ importers: version: 14.0.0(webpack@5.106.2(esbuild@0.28.0)) css-loader: specifier: ^7.1.4 - version: 7.1.4(webpack@5.106.2(esbuild@0.28.0)) + version: 7.1.4(@rspack/core@2.0.3)(webpack@5.106.2(esbuild@0.28.0)) css-minimizer-webpack-plugin: specifier: ^8.0.0 version: 8.0.0(esbuild@0.28.0)(lightningcss@1.32.0)(webpack@5.106.2(esbuild@0.28.0)) @@ -238,7 +304,7 @@ importers: version: 4.22.1 html-webpack-plugin: specifier: ^5.6.7 - version: 5.6.7(webpack@5.106.2(esbuild@0.28.0)) + version: 5.6.7(@rspack/core@2.0.3)(webpack@5.106.2(esbuild@0.28.0)) lightningcss: specifier: ^1.32.0 version: 1.32.0 @@ -250,7 +316,7 @@ importers: version: 8.5.14 postcss-loader: specifier: ^8.2.1 - version: 8.2.1(postcss@8.5.14)(typescript@6.0.3)(webpack@5.106.2(esbuild@0.28.0)) + version: 8.2.1(@rspack/core@2.0.3)(postcss@8.5.14)(typescript@6.0.3)(webpack@5.106.2(esbuild@0.28.0)) style-loader: specifier: ^4.0.0 version: 4.0.0(webpack@5.106.2(esbuild@0.28.0)) @@ -1772,6 +1838,93 @@ packages: '@rolldown/pluginutils@1.0.0-rc.18': resolution: {integrity: sha512-CUY5Mnhe64xQBGZEEXQ5WyZwsc1JU3vAZLIxtrsBt3LO6UOb+C8GunVKqe9sT8NeWb4lqSaoJtp2xo6GxT1MNw==} + '@rspack/binding-darwin-arm64@2.0.3': + resolution: {integrity: sha512-4UyCjLJwU/WxR6K1/gG4u3+jUsoaRHJ5rNu9fto/UbvrItwdlVNULChAApqZFw6mcSetMddSjSICeuj5pSB6sA==} + cpu: [arm64] + os: [darwin] + + '@rspack/binding-darwin-x64@2.0.3': + resolution: {integrity: sha512-K3evrbTgZNa8emEqk+AjDtbuoXZp5tPZz3pcEgETxuu3KanW8Zu+Fb+TUp1DEUcL0xOmHPPox8H2cZ3pF4Zmug==} + cpu: [x64] + os: [darwin] + + '@rspack/binding-linux-arm64-gnu@2.0.3': + resolution: {integrity: sha512-aPLDaaTtX1wqjLYAIHc2MGDQZtv1Hbjx47oaaefbWz5GbAnSA4P8jdYIeeGRyrqvQ0WqJXIWXgT0d/iXtes00A==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rspack/binding-linux-arm64-musl@2.0.3': + resolution: {integrity: sha512-0WulUQPop6vmSDfrTxghmVlm+6crU8/XqD2f0dOWbEniZVuDZJ5/Y/cBqTRyk3rjl0vrmUv3lc87/t7UgQJQSw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rspack/binding-linux-x64-gnu@2.0.3': + resolution: {integrity: sha512-fAhiMuV5omT53YMft+f3Y9euAFgspuyBAk9ZpeW2buL2TkuUMwP07adhhvQfKdQ5gpELfzmjQaRDGqaIT8UWiA==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rspack/binding-linux-x64-musl@2.0.3': + resolution: {integrity: sha512-0kcuFoZ8vy2iNWoISFOZt+/Ujo7LRLrzE7h07AV5r+oN/mv+/v14Sd/8NUtDIScCkrYOszYq/QS31e6t0UrVfw==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rspack/binding-wasm32-wasi@2.0.3': + resolution: {integrity: sha512-x2fsw7GzNZEnw444ikj4/b8kVjM0Y0TllxmizHpYZ9gmaQrOk5OXo9RQdz+l4zzoGors0l2IZP5Cc4GJNCaSoQ==} + cpu: [wasm32] + + '@rspack/binding-win32-arm64-msvc@2.0.3': + resolution: {integrity: sha512-jqlxuVPdrgMuwj/HEjSkC/jmhl4fAuKyob36zJXq2uAusn2FRJ4kClGe1fLFpfxRXFVQAWwlAOwLJg8T0suuaA==} + cpu: [arm64] + os: [win32] + + '@rspack/binding-win32-ia32-msvc@2.0.3': + resolution: {integrity: sha512-QM4JEuyk5QaZ5gnvnAIaCwVQzCkrD2E4Sud77kx/MVGDsRkcOlMx3blMC5QNHPDamRmWGk+7314YOQvRhKuWyg==} + cpu: [ia32] + os: [win32] + + '@rspack/binding-win32-x64-msvc@2.0.3': + resolution: {integrity: sha512-vSQNnAy0wswG6AfNRuArTHQBiXOXl+A9ddQxBFup4PMHUzXxKtsBLQzw7BgFC0EgrPeHbt+30j7sXVZKYukj4A==} + cpu: [x64] + os: [win32] + + '@rspack/binding@2.0.3': + resolution: {integrity: sha512-4exVNhGhW5RFHjK87XeTKbkA/qAgI5NHJlT1jNqiJv0gcUXLqTOEU3w7f8+f9zUo4JMFvPc0c9veOi4M19YYTg==} + + '@rspack/core@2.0.3': + resolution: {integrity: sha512-2ufO/8FHIA/lX6UOgSsKPhpDvHr0sh9lYq/n/LsIZsTwu3973BGbu2fg1Akvuu3rEnskPqXjsqH2EPBzEA42uA==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@module-federation/runtime-tools': ^0.24.1 || ^2.0.0 + '@swc/helpers': '>=0.5.1' + peerDependenciesMeta: + '@module-federation/runtime-tools': + optional: true + '@swc/helpers': + optional: true + + '@rspack/dev-middleware@2.0.1': + resolution: {integrity: sha512-cXSubf5/C+dvkWV2/+rGTtiZ93wSLd3OlTQhwMvsmsmGDdPlkYqIvQ+BTkOk9UCXxKIaF0DDYYmCpBeRRYJfJw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@rspack/core': ^2.0.0-0 + peerDependenciesMeta: + '@rspack/core': + optional: true + + '@rspack/dev-server@2.0.1': + resolution: {integrity: sha512-N5sIdU9v6WhwPH6Ek8QCj4IMvGd8jA3ZW1NMAyHP1ezzKIr2/idcNV2zX5vbC6FJvOLRLww0rFjfKA+z4tshDA==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@rspack/core': ^2.0.0-0 + selfsigned: ^5.0.0 + peerDependenciesMeta: + selfsigned: + optional: true + '@simple-libs/child-process-utils@1.0.2': resolution: {integrity: sha512-/4R8QKnd/8agJynkNdJmNw2MBxuFTRcNFnE5Sg/G+jkSsV8/UBgULMzhizWWW42p8L5H7flImV2ATi79Ove2Tw==} engines: {node: '>=18'} @@ -4793,6 +4946,17 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + rspack-chain@2.0.1: + resolution: {integrity: sha512-/ePnFJvIDiIn/nMB7JI42Sju8oGRfUbKTV+1Vg2GnZpXktmTVZNJMQe7+VCfG9YTN66ZW7Qc51Q8SDN0mr6e0w==} + peerDependencies: + '@rspack/core': ^2.0.0-0 + peerDependenciesMeta: + '@rspack/core': + optional: true + + rspack-merge@0.1.1: + resolution: {integrity: sha512-RHKi8nECjP0lM1V7RnM+8G8dRvWgrsnntzfogJQz7oSHo104ca4jsL3KN/0gru233n/lVGrqDPDNlCA4x0UNlg==} + run-applescript@7.1.0: resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} engines: {node: '>=18'} @@ -6241,7 +6405,7 @@ snapshots: '@jest/pattern@30.0.1': dependencies: - '@types/node': 25.6.0 + '@types/node': 24.12.3 jest-regex-util: 30.0.1 '@jest/schemas@30.0.5': @@ -6834,6 +6998,68 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.18': {} + '@rspack/binding-darwin-arm64@2.0.3': + optional: true + + '@rspack/binding-darwin-x64@2.0.3': + optional: true + + '@rspack/binding-linux-arm64-gnu@2.0.3': + optional: true + + '@rspack/binding-linux-arm64-musl@2.0.3': + optional: true + + '@rspack/binding-linux-x64-gnu@2.0.3': + optional: true + + '@rspack/binding-linux-x64-musl@2.0.3': + optional: true + + '@rspack/binding-wasm32-wasi@2.0.3': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@rspack/binding-win32-arm64-msvc@2.0.3': + optional: true + + '@rspack/binding-win32-ia32-msvc@2.0.3': + optional: true + + '@rspack/binding-win32-x64-msvc@2.0.3': + optional: true + + '@rspack/binding@2.0.3': + optionalDependencies: + '@rspack/binding-darwin-arm64': 2.0.3 + '@rspack/binding-darwin-x64': 2.0.3 + '@rspack/binding-linux-arm64-gnu': 2.0.3 + '@rspack/binding-linux-arm64-musl': 2.0.3 + '@rspack/binding-linux-x64-gnu': 2.0.3 + '@rspack/binding-linux-x64-musl': 2.0.3 + '@rspack/binding-wasm32-wasi': 2.0.3 + '@rspack/binding-win32-arm64-msvc': 2.0.3 + '@rspack/binding-win32-ia32-msvc': 2.0.3 + '@rspack/binding-win32-x64-msvc': 2.0.3 + + '@rspack/core@2.0.3': + dependencies: + '@rspack/binding': 2.0.3 + + '@rspack/dev-middleware@2.0.1(@rspack/core@2.0.3)': + optionalDependencies: + '@rspack/core': 2.0.3 + + '@rspack/dev-server@2.0.1(@rspack/core@2.0.3)(selfsigned@5.5.0)': + dependencies: + '@rspack/core': 2.0.3 + '@rspack/dev-middleware': 2.0.1(@rspack/core@2.0.3) + optionalDependencies: + selfsigned: 5.5.0 + '@simple-libs/child-process-utils@1.0.2': dependencies: '@simple-libs/stream-utils': 1.2.0 @@ -6858,7 +7084,7 @@ snapshots: '@types/bonjour@3.5.13': dependencies: - '@types/node': 25.6.0 + '@types/node': 24.12.3 '@types/chai@5.2.3': dependencies: @@ -6934,7 +7160,7 @@ snapshots: '@types/http-proxy@1.17.17': dependencies: - '@types/node': 25.6.0 + '@types/node': 24.12.3 '@types/istanbul-lib-coverage@2.0.6': {} @@ -7016,7 +7242,7 @@ snapshots: '@types/sockjs@0.3.36': dependencies: - '@types/node': 25.6.0 + '@types/node': 24.12.3 '@types/unist@3.0.3': {} @@ -7024,7 +7250,7 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 25.6.0 + '@types/node': 24.12.3 '@types/yargs-parser@21.0.3': {} @@ -7929,7 +8155,7 @@ snapshots: dependencies: postcss: 8.5.14 - css-loader@7.1.4(webpack@5.106.2(esbuild@0.28.0)): + css-loader@7.1.4(@rspack/core@2.0.3)(webpack@5.106.2(esbuild@0.28.0)): dependencies: icss-utils: 5.1.0(postcss@8.5.14) postcss: 8.5.14 @@ -7940,6 +8166,7 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.7.4 optionalDependencies: + '@rspack/core': 2.0.3 webpack: 5.106.2(esbuild@0.28.0) css-minimizer-webpack-plugin@8.0.0(esbuild@0.28.0)(lightningcss@1.32.0)(webpack@5.106.2(esbuild@0.28.0)): @@ -8702,7 +8929,7 @@ snapshots: relateurl: 0.2.7 terser: 5.46.2 - html-webpack-plugin@5.6.7(webpack@5.106.2(esbuild@0.28.0)): + html-webpack-plugin@5.6.7(@rspack/core@2.0.3)(webpack@5.106.2(esbuild@0.28.0)): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -8710,6 +8937,7 @@ snapshots: pretty-error: 4.0.0 tapable: 2.3.3 optionalDependencies: + '@rspack/core': 2.0.3 webpack: 5.106.2(esbuild@0.28.0) htmlparser2@6.1.0: @@ -9827,13 +10055,14 @@ snapshots: postcss: 8.5.14 yaml: 2.8.4 - postcss-loader@8.2.1(postcss@8.5.14)(typescript@6.0.3)(webpack@5.106.2(esbuild@0.28.0)): + postcss-loader@8.2.1(@rspack/core@2.0.3)(postcss@8.5.14)(typescript@6.0.3)(webpack@5.106.2(esbuild@0.28.0)): dependencies: cosmiconfig: 9.0.1(typescript@6.0.3) jiti: 2.7.0 postcss: 8.5.14 semver: 7.7.4 optionalDependencies: + '@rspack/core': 2.0.3 webpack: 5.106.2(esbuild@0.28.0) transitivePeerDependencies: - typescript @@ -10170,6 +10399,12 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.18 '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.18 + rspack-chain@2.0.1(@rspack/core@2.0.3): + optionalDependencies: + '@rspack/core': 2.0.3 + + rspack-merge@0.1.1: {} + run-applescript@7.1.0: {} rxjs@7.8.2: @@ -10269,10 +10504,11 @@ snapshots: sass-embedded-win32-arm64: 1.99.0 sass-embedded-win32-x64: 1.99.0 - sass-loader@16.0.7(sass-embedded@1.99.0)(sass@1.99.0)(webpack@5.106.2(esbuild@0.28.0)): + sass-loader@16.0.7(@rspack/core@2.0.3)(sass-embedded@1.99.0)(sass@1.99.0)(webpack@5.106.2(esbuild@0.28.0)): dependencies: neo-async: 2.6.2 optionalDependencies: + '@rspack/core': 2.0.3 sass: 1.99.0 sass-embedded: 1.99.0 webpack: 5.106.2(esbuild@0.28.0) From 135d455ac49dec5a23b9a6c973e2154311adeff6 Mon Sep 17 00:00:00 2001 From: "Mr.Hope" Date: Thu, 14 May 2026 16:18:32 +0800 Subject: [PATCH 02/13] chore: tweaks --- packages/bundler-rspack/package.json | 1 + .../src/config/handleModulePug.ts | 4 +- .../bundler-rspack/src/dev/createDevConfig.ts | 8 +- pnpm-lock.yaml | 287 ++++++++++++++++++ 4 files changed, 294 insertions(+), 6 deletions(-) diff --git a/packages/bundler-rspack/package.json b/packages/bundler-rspack/package.json index d56c5c587d..8d8230bb38 100644 --- a/packages/bundler-rspack/package.json +++ b/packages/bundler-rspack/package.json @@ -41,6 +41,7 @@ "clean": "rimraf dist" }, "dependencies": { + "@rsbuild/plugin-pug": "^1.3.3", "@rspack/core": "^2.0.3", "@rspack/dev-server": "^2.0.1", "@types/express": "^4.17.25", diff --git a/packages/bundler-rspack/src/config/handleModulePug.ts b/packages/bundler-rspack/src/config/handleModulePug.ts index ce937d0944..f145b33ead 100644 --- a/packages/bundler-rspack/src/config/handleModulePug.ts +++ b/packages/bundler-rspack/src/config/handleModulePug.ts @@ -7,6 +7,6 @@ export const handleModulePug = ({ config }: { config: RspackChain }): void => { config.module .rule('pug') .test(/\.pug$/) - .use('pug-plain-loader') - .loader('pug-plain-loader') + .use('pug-loader') + .loader('@rsbuild/plugin-pug') } diff --git a/packages/bundler-rspack/src/dev/createDevConfig.ts b/packages/bundler-rspack/src/dev/createDevConfig.ts index e93c75b60a..8b9b125c47 100644 --- a/packages/bundler-rspack/src/dev/createDevConfig.ts +++ b/packages/bundler-rspack/src/dev/createDevConfig.ts @@ -1,7 +1,7 @@ +import { HotModuleReplacementPlugin } from '@rspack/core' import type { App } from '@vuepress/core' import HtmlPlugin from 'html-webpack-plugin' -import webpack from 'webpack' -import type { Config } from 'webpack-v5-chain' +import type { RspackChain } from 'rspack-chain' import { createClientBaseConfig } from '../config/index.js' import type { RspackBundlerOptions } from '../types.js' @@ -9,7 +9,7 @@ import type { RspackBundlerOptions } from '../types.js' export const createDevConfig = async ( app: App, options: RspackBundlerOptions, -): Promise => { +): Promise => { const config = await createClientBaseConfig({ app, options, @@ -22,7 +22,7 @@ export const createDevConfig = async ( }, ]) - config.plugin('hmr').use(webpack.HotModuleReplacementPlugin) + config.plugin('hmr').use(HotModuleReplacementPlugin) return config } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9b69cb0e11..be6e96f0c7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -148,6 +148,9 @@ importers: packages/bundler-rspack: dependencies: + '@rsbuild/plugin-pug': + specifier: ^1.3.3 + version: 1.3.3 '@rspack/core': specifier: ^2.0.3 version: 2.0.3 @@ -1838,6 +1841,14 @@ packages: '@rolldown/pluginutils@1.0.0-rc.18': resolution: {integrity: sha512-CUY5Mnhe64xQBGZEEXQ5WyZwsc1JU3vAZLIxtrsBt3LO6UOb+C8GunVKqe9sT8NeWb4lqSaoJtp2xo6GxT1MNw==} + '@rsbuild/plugin-pug@1.3.3': + resolution: {integrity: sha512-shNzKSXhZm+yGB2KYOGIAi7MOxe566oKgONbILh53k9wpT9h6OFZWo5cGm33JZ8Y8HCc199WtxaE0U2Jy6zj/w==} + peerDependencies: + '@rsbuild/core': ^1.0.0 || ^2.0.0 + peerDependenciesMeta: + '@rsbuild/core': + optional: true + '@rspack/binding-darwin-arm64@2.0.3': resolution: {integrity: sha512-4UyCjLJwU/WxR6K1/gG4u3+jUsoaRHJ5rNu9fto/UbvrItwdlVNULChAApqZFw6mcSetMddSjSICeuj5pSB6sA==} cpu: [arm64] @@ -2063,6 +2074,9 @@ packages: '@types/picomatch@4.0.3': resolution: {integrity: sha512-iG0T6+nYJ9FAPmx9SsUlnwcq1ZVRuCXcVEvWnntoPlrOpwtSTKNDC9uVAxTsC3PUvJ+99n4RpAcNgBbHX3JSnQ==} + '@types/pug@2.0.10': + resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==} + '@types/qs@6.15.1': resolution: {integrity: sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==} @@ -2455,6 +2469,11 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn@7.4.1: + resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} + engines: {node: '>=0.4.0'} + hasBin: true + acorn@8.16.0: resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} @@ -2542,10 +2561,16 @@ packages: array-ify@1.0.0: resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + asn1js@3.0.10: resolution: {integrity: sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==} engines: {node: '>=12.0.0'} + assert-never@1.4.0: + resolution: {integrity: sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -2569,6 +2594,10 @@ packages: peerDependencies: postcss: ^8.1.0 + babel-walk@3.0.0-canary-5: + resolution: {integrity: sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==} + engines: {node: '>= 10.0.0'} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -2706,6 +2735,9 @@ packages: character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + character-parser@2.2.0: + resolution: {integrity: sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -2817,6 +2849,9 @@ packages: resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} engines: {node: '>=0.8'} + constantinople@4.0.1: + resolution: {integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==} + content-disposition@0.5.2: resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==} engines: {node: '>= 0.6'} @@ -3079,6 +3114,9 @@ packages: resolution: {integrity: sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==} engines: {node: '>=6'} + doctypes@1.1.0: + resolution: {integrity: sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==} + dom-converter@0.2.0: resolution: {integrity: sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==} @@ -3598,6 +3636,10 @@ packages: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + hash-sum@2.0.0: resolution: {integrity: sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==} @@ -3746,6 +3788,10 @@ packages: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} + is-core-module@2.16.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} + engines: {node: '>= 0.4'} + is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} @@ -3756,6 +3802,9 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} hasBin: true + is-expression@4.0.0: + resolution: {integrity: sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==} + is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} engines: {node: '>=0.10.0'} @@ -3813,6 +3862,13 @@ packages: resolution: {integrity: sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + is-promise@2.2.2: + resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -3878,6 +3934,9 @@ packages: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true + js-stringify@1.0.2: + resolution: {integrity: sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3924,6 +3983,9 @@ packages: jsonfile@6.2.1: resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} + jstransformer@1.0.0: + resolution: {integrity: sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==} + katex@0.16.45: resolution: {integrity: sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==} hasBin: true @@ -4410,6 +4472,10 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} @@ -4506,6 +4572,9 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@2.0.2: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} @@ -4794,10 +4863,49 @@ packages: process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + promise@7.3.1: + resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + pug-attrs@3.0.0: + resolution: {integrity: sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==} + + pug-code-gen@3.0.4: + resolution: {integrity: sha512-6okWYIKdasTyXICyEtvobmTZAVX57JkzgzIi4iRJlin8kmhG+Xry2dsus+Mun/nGCn6F2U49haHI5mkELXB14g==} + + pug-error@2.1.0: + resolution: {integrity: sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==} + + pug-filters@4.0.0: + resolution: {integrity: sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==} + + pug-lexer@5.0.1: + resolution: {integrity: sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==} + + pug-linker@4.0.0: + resolution: {integrity: sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==} + + pug-load@3.0.0: + resolution: {integrity: sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==} + + pug-parser@6.0.0: + resolution: {integrity: sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==} + + pug-runtime@3.0.1: + resolution: {integrity: sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==} + + pug-strip-comments@2.0.0: + resolution: {integrity: sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==} + + pug-walk@2.0.0: + resolution: {integrity: sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==} + + pug@3.0.4: + resolution: {integrity: sha512-kFfq5mMzrS7+wrl5pLJzZEzemx34OQ0w4SARfhy/3yxTlhbstsudDwJzhf1hP02yHzbjoVMSXUj/Sz6RNfMyXg==} + punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} @@ -4862,6 +4970,9 @@ packages: resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} engines: {node: '>= 20.19.0'} + reduce-configs@1.1.2: + resolution: {integrity: sha512-AgBP55V8FC7NaqoOP2RCbTpu6LE+YuX3LUZkNAoitcfyS3/PIC8Obg/TJrBzTkJ+lDvZv0TTAeDpLkzjTtYlbw==} + reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} @@ -4901,6 +5012,11 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} + engines: {node: '>= 0.4'} + hasBin: true + restore-cursor@5.1.0: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} engines: {node: '>=18'} @@ -5348,6 +5464,10 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + svgo@4.0.1: resolution: {integrity: sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==} engines: {node: '>=16'} @@ -5430,6 +5550,9 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + token-stream@1.0.0: + resolution: {integrity: sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==} + tree-dump@1.1.0: resolution: {integrity: sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==} engines: {node: '>=10.0'} @@ -5689,6 +5812,10 @@ packages: jsdom: optional: true + void-elements@3.1.0: + resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} + engines: {node: '>=0.10.0'} + vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} @@ -5822,6 +5949,10 @@ packages: wildcard@2.0.1: resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} + with@7.0.2: + resolution: {integrity: sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==} + engines: {node: '>= 10.0.0'} + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -6998,6 +7129,13 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.18': {} + '@rsbuild/plugin-pug@1.3.3': + dependencies: + '@types/pug': 2.0.10 + lodash: 4.18.1 + pug: 3.0.4 + reduce-configs: 1.1.2 + '@rspack/binding-darwin-arm64@2.0.3': optional: true @@ -7215,6 +7353,8 @@ snapshots: '@types/picomatch@4.0.3': {} + '@types/pug@2.0.10': {} + '@types/qs@6.15.1': {} '@types/range-parser@1.2.7': {} @@ -7695,6 +7835,8 @@ snapshots: dependencies: acorn: 8.16.0 + acorn@7.4.1: {} + acorn@8.16.0: {} ajv-formats@2.1.1(ajv@8.20.0): @@ -7772,12 +7914,16 @@ snapshots: array-ify@1.0.0: {} + asap@2.0.6: {} + asn1js@3.0.10: dependencies: pvtsutils: 1.3.6 pvutils: 1.1.5 tslib: 2.8.1 + assert-never@1.4.0: {} + assertion-error@2.0.1: {} ast-kit@2.2.0: @@ -7805,6 +7951,10 @@ snapshots: postcss: 8.5.14 postcss-value-parser: 4.2.0 + babel-walk@3.0.0-canary-5: + dependencies: + '@babel/types': 7.29.0 + balanced-match@1.0.2: {} balanced-match@4.0.4: {} @@ -7950,6 +8100,10 @@ snapshots: character-entities@2.0.2: {} + character-parser@2.2.0: + dependencies: + is-regex: 1.2.1 + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -8060,6 +8214,11 @@ snapshots: connect-history-api-fallback@2.0.0: {} + constantinople@4.0.1: + dependencies: + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + content-disposition@0.5.2: {} content-disposition@0.5.4: @@ -8315,6 +8474,8 @@ snapshots: dependencies: '@leichtgewicht/ip-codec': 2.0.5 + doctypes@1.1.0: {} + dom-converter@0.2.0: dependencies: utila: 0.4.0 @@ -8894,6 +9055,10 @@ snapshots: has-symbols@1.1.0: {} + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + hash-sum@2.0.0: {} hasown@2.0.3: @@ -9034,10 +9199,19 @@ snapshots: dependencies: binary-extensions: 2.3.0 + is-core-module@2.16.2: + dependencies: + hasown: 2.0.3 + is-docker@2.2.1: {} is-docker@3.0.0: {} + is-expression@4.0.0: + dependencies: + acorn: 7.4.1 + object-assign: 4.1.1 + is-extendable@0.1.1: {} is-extglob@2.1.1: {} @@ -9074,6 +9248,15 @@ snapshots: is-port-reachable@4.0.0: {} + is-promise@2.2.2: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.3 + is-stream@2.0.1: {} is-unicode-supported@2.1.0: {} @@ -9136,6 +9319,8 @@ snapshots: jiti@2.7.0: {} + js-stringify@1.0.2: {} + js-tokens@4.0.0: {} js-yaml@3.14.2: @@ -9175,6 +9360,11 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jstransformer@1.0.0: + dependencies: + is-promise: 2.2.2 + promise: 7.3.1 + katex@0.16.45: dependencies: commander: 8.3.0 @@ -9832,6 +10022,8 @@ snapshots: dependencies: boolbase: 1.0.0 + object-assign@4.1.1: {} + object-inspect@1.13.4: {} obuf@1.1.2: {} @@ -9958,6 +10150,8 @@ snapshots: path-key@3.1.1: {} + path-parse@1.0.7: {} + path-scurry@2.0.2: dependencies: lru-cache: 11.3.6 @@ -10224,11 +10418,82 @@ snapshots: process-nextick-args@2.0.1: {} + promise@7.3.1: + dependencies: + asap: 2.0.6 + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 ipaddr.js: 1.9.1 + pug-attrs@3.0.0: + dependencies: + constantinople: 4.0.1 + js-stringify: 1.0.2 + pug-runtime: 3.0.1 + + pug-code-gen@3.0.4: + dependencies: + constantinople: 4.0.1 + doctypes: 1.1.0 + js-stringify: 1.0.2 + pug-attrs: 3.0.0 + pug-error: 2.1.0 + pug-runtime: 3.0.1 + void-elements: 3.1.0 + with: 7.0.2 + + pug-error@2.1.0: {} + + pug-filters@4.0.0: + dependencies: + constantinople: 4.0.1 + jstransformer: 1.0.0 + pug-error: 2.1.0 + pug-walk: 2.0.0 + resolve: 1.22.12 + + pug-lexer@5.0.1: + dependencies: + character-parser: 2.2.0 + is-expression: 4.0.0 + pug-error: 2.1.0 + + pug-linker@4.0.0: + dependencies: + pug-error: 2.1.0 + pug-walk: 2.0.0 + + pug-load@3.0.0: + dependencies: + object-assign: 4.1.1 + pug-walk: 2.0.0 + + pug-parser@6.0.0: + dependencies: + pug-error: 2.1.0 + token-stream: 1.0.0 + + pug-runtime@3.0.1: {} + + pug-strip-comments@2.0.0: + dependencies: + pug-error: 2.1.0 + + pug-walk@2.0.0: {} + + pug@3.0.4: + dependencies: + pug-code-gen: 3.0.4 + pug-filters: 4.0.0 + pug-lexer: 5.0.1 + pug-linker: 4.0.0 + pug-load: 3.0.0 + pug-parser: 6.0.0 + pug-runtime: 3.0.1 + pug-strip-comments: 2.0.0 + punycode.js@2.3.1: {} punycode@2.3.1: {} @@ -10293,6 +10558,8 @@ snapshots: readdirp@5.0.0: {} + reduce-configs@1.1.2: {} + reflect-metadata@0.2.2: {} registry-auth-token@3.3.2: @@ -10326,6 +10593,13 @@ snapshots: resolve-pkg-maps@1.0.0: {} + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.2 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@5.1.0: dependencies: onetime: 7.0.0 @@ -10802,6 +11076,8 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} + svgo@4.0.1: dependencies: commander: 11.1.0 @@ -10882,6 +11158,8 @@ snapshots: toidentifier@1.0.1: {} + token-stream@1.0.0: {} + tree-dump@1.1.0(tslib@2.8.1): dependencies: tslib: 2.8.1 @@ -11121,6 +11399,8 @@ snapshots: transitivePeerDependencies: - msw + void-elements@3.1.0: {} + vscode-uri@3.1.0: {} vue-eslint-parser@10.4.0(eslint@10.3.0(jiti@2.7.0)): @@ -11316,6 +11596,13 @@ snapshots: wildcard@2.0.1: {} + with@7.0.2: + dependencies: + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + assert-never: 1.4.0 + babel-walk: 3.0.0-canary-5 + word-wrap@1.2.5: {} wordwrap@1.0.0: {} From 03815578f3ad6c6e6ae918bdebd8913fc920dcd3 Mon Sep 17 00:00:00 2001 From: "Mr.Hope" Date: Thu, 14 May 2026 17:23:16 +0800 Subject: [PATCH 03/13] feat: init rspack --- packages/bundler-rspack/package.json | 6 ++-- packages/bundler-rspack/src/build/build.ts | 34 +++++++++++-------- .../src/build/createClientConfig.ts | 6 ++-- .../src/build/createClientPlugin.ts | 10 +++--- .../src/build/createServerConfig.ts | 6 ++-- .../bundler-rspack/src/build/renderPage.ts | 4 +-- packages/bundler-rspack/src/build/types.ts | 2 +- .../src/config/handleDevtool.ts | 2 +- .../src/config/handleModuleAssets.ts | 2 +- .../src/config/handleModuleJs.ts | 2 +- .../src/config/handleModulePug.ts | 2 +- .../src/config/handleModuleStyles.ts | 2 +- .../src/config/handleModuleTs.ts | 2 +- .../src/config/handleModuleVue.ts | 2 +- .../bundler-rspack/src/config/handleNode.ts | 2 +- .../src/config/handleOtherOptions.ts | 5 +-- .../bundler-rspack/src/dev/createDevConfig.ts | 5 ++- .../src/dev/createDevServerConfig.ts | 6 ++-- packages/bundler-rspack/src/dev/dev.ts | 32 +++++++++-------- .../src/dev/trailingSlashMiddleware.ts | 29 ++++++++++++---- .../src/loaders/vuepressMarkdownLoader.ts | 4 +-- .../src/loaders/vuepressSsrLoader.ts | 4 +-- packages/bundler-rspack/src/types.ts | 3 +- pnpm-lock.yaml | 24 ++++++------- 24 files changed, 109 insertions(+), 87 deletions(-) diff --git a/packages/bundler-rspack/package.json b/packages/bundler-rspack/package.json index 8d8230bb38..4535aa5868 100644 --- a/packages/bundler-rspack/package.json +++ b/packages/bundler-rspack/package.json @@ -44,7 +44,6 @@ "@rsbuild/plugin-pug": "^1.3.3", "@rspack/core": "^2.0.3", "@rspack/dev-server": "^2.0.1", - "@types/express": "^4.17.25", "@vuepress/bundlerutils": "workspace:*", "@vuepress/client": "workspace:*", "@vuepress/core": "workspace:*", @@ -53,8 +52,6 @@ "autoprefixer": "^10.5.0", "css-loader": "^7.1.4", "esbuild-loader": "~4.4.3", - "express": "^4.22.1", - "html-webpack-plugin": "^5.6.7", "postcss": "^8.5.14", "postcss-loader": "^8.2.1", "rspack-chain": "^2.0.1", @@ -63,5 +60,8 @@ "vue": "catalog:vue", "vue-loader": "^17.4.2", "vue-router": "catalog:vue" + }, + "devDependencies": { + "connect-next": "^4.0.1" } } diff --git a/packages/bundler-rspack/src/build/build.ts b/packages/bundler-rspack/src/build/build.ts index 866931f643..b7d8b3345a 100644 --- a/packages/bundler-rspack/src/build/build.ts +++ b/packages/bundler-rspack/src/build/build.ts @@ -1,8 +1,8 @@ +import { rspack } from '@rspack/core' +import type { MultiRspackOptions } from '@rspack/core' import { createVueServerApp, getSsrTemplate } from '@vuepress/bundlerutils' import type { App, Bundler } from '@vuepress/core' import { colors, debug, fs, logger, withSpinner } from '@vuepress/utils' -import type { MultiConfiguration } from 'webpack' -import webpack from 'webpack' import { resolveRspackConfig } from '../resolveRspackConfig.js' import type { RspackBundlerOptions } from '../types.js' @@ -15,7 +15,7 @@ import { renderPage } from './renderPage.js' import { resolveClientManifestMeta } from './resolveClientManifestMeta.js' import type { ClientManifest } from './types.js' -const log = debug('vuepress:bundler-webpack/build') +const log = debug('vuepress:bundler-rspack/build') export const build = async ( options: RspackBundlerOptions, @@ -24,10 +24,10 @@ export const build = async ( // plugin hook: extendsBundlerOptions await app.pluginApi.hooks.extendsBundlerOptions.process(options, app) - // webpack compile + // rspack compile log('compiling start') - await withSpinner('Compiling with webpack')(async () => { - // create webpack config + await withSpinner('Compiling with rspack')(async () => { + // create rspack config const clientConfig = resolveRspackConfig({ config: await createClientConfig(app, options), options, @@ -42,22 +42,26 @@ export const build = async ( }) await new Promise((resolve, reject) => { - webpack( - [clientConfig, serverConfig] as MultiConfiguration, + rspack( + [clientConfig, serverConfig] as MultiRspackOptions, (err, stats) => { if (err) { reject(err) - } else if (stats?.hasErrors()) { - stats.toJson().errors?.forEach((item) => { - logger.error(item) - }) - reject(new Error('Failed to compile with errors')) } else { - if (stats?.hasWarnings()) { - stats.toJson().warnings?.forEach((warning) => { + if (stats) { + const { warnings, errors } = stats.toJson('errors-warnings') + + errors?.forEach((item) => { + logger.error(item) + }) + warnings?.forEach((warning) => { logger.warn(warning) }) + + if (stats.hasErrors()) + reject(new Error('Failed to compile with errors')) } + resolve() } }, diff --git a/packages/bundler-rspack/src/build/createClientConfig.ts b/packages/bundler-rspack/src/build/createClientConfig.ts index faaf5fc0dc..a4d9a509b9 100644 --- a/packages/bundler-rspack/src/build/createClientConfig.ts +++ b/packages/bundler-rspack/src/build/createClientConfig.ts @@ -3,10 +3,10 @@ import { CssExtractRspackPlugin, LightningCssMinimizerRspackPlugin, } from '@rspack/core' +import type { Module } from '@rspack/core' import type { App } from '@vuepress/core' import { fs } from '@vuepress/utils' -import type { Module } from 'webpack' -import type { Config } from 'webpack-v5-chain' +import type { RspackChain } from 'rspack-chain' import { createClientBaseConfig } from '../config/index.js' import type { RspackBundlerOptions } from '../types.js' @@ -20,7 +20,7 @@ export const CLIENT_MANIFEST_FILENAME = '.server/client-manifest.json' export const createClientConfig = async ( app: App, options: RspackBundlerOptions, -): Promise => { +): Promise => { const config = await createClientBaseConfig({ app, options, diff --git a/packages/bundler-rspack/src/build/createClientPlugin.ts b/packages/bundler-rspack/src/build/createClientPlugin.ts index 8e39036dd0..1af2b7ddd5 100644 --- a/packages/bundler-rspack/src/build/createClientPlugin.ts +++ b/packages/bundler-rspack/src/build/createClientPlugin.ts @@ -1,5 +1,5 @@ +import type { RspackPluginInstance, StatsModule } from '@rspack/core' import { fs } from '@vuepress/utils' -import type { StatsModule, WebpackPluginInstance } from 'webpack' import type { ClientManifest } from './types.js' @@ -10,17 +10,17 @@ const isCSS = (file: string): boolean => /\.css(\?[^.]+)?$/.test(file) /** * Vuepress client plugin * - * Collecting webpack bundled files info for SSR + * Collecting rspack bundled files info for SSR */ export const createClientPlugin = ( outputFile: string, -): WebpackPluginInstance => { - const clientPlugin: WebpackPluginInstance = { +): RspackPluginInstance => { + const clientPlugin: RspackPluginInstance = { apply(compiler) { compiler.hooks.emit.tapPromise( 'vuepress-client-plugin', async (compilation) => { - // get webpack stats object + // get rspack stats object const { assets = [], modules = [], diff --git a/packages/bundler-rspack/src/build/createServerConfig.ts b/packages/bundler-rspack/src/build/createServerConfig.ts index 76a39dfe5a..2eba869e0b 100644 --- a/packages/bundler-rspack/src/build/createServerConfig.ts +++ b/packages/bundler-rspack/src/build/createServerConfig.ts @@ -1,5 +1,5 @@ import type { App } from '@vuepress/core' -import type { Config } from 'webpack-v5-chain' +import type { RspackChain } from 'rspack-chain' import { createBaseConfig } from '../config/index.js' import type { RspackBundlerOptions } from '../types.js' @@ -7,7 +7,7 @@ import type { RspackBundlerOptions } from '../types.js' export const createServerConfig = async ( app: App, options: RspackBundlerOptions, -): Promise => { +): Promise => { const isBuild = true const isServer = true @@ -24,7 +24,7 @@ export const createServerConfig = async ( .path(app.dir.temp('.server')) .filename('app.cjs') .publicPath(app.options.base) - .libraryTarget('commonjs2') + .library({ type: 'commonjs2' }) // set target to node // vue-loader will use compiler-ssr internally diff --git a/packages/bundler-rspack/src/build/renderPage.ts b/packages/bundler-rspack/src/build/renderPage.ts index 2608faff9e..1f4a90ede1 100644 --- a/packages/bundler-rspack/src/build/renderPage.ts +++ b/packages/bundler-rspack/src/build/renderPage.ts @@ -12,7 +12,7 @@ import { renderPageStyles } from './renderPageStyles.js' import { resolvePageClientFilesMeta } from './resolvePageClientFilesMeta.js' import type { FileMeta, ModuleFilesMetaMap } from './types.js' -interface WebpackPageSSRContext extends PageSSRContext { +interface RspackPageSSRContext extends PageSSRContext { /** * Injected by vuepress-ssr-loader * @@ -45,7 +45,7 @@ export const renderPage = async ({ }): Promise => { // render current page to string const { ssrContext, ssrString } = - await renderPageToString({ + await renderPageToString({ page, vueApp, vueRouter, diff --git a/packages/bundler-rspack/src/build/types.ts b/packages/bundler-rspack/src/build/types.ts index 5eaf515096..11df28d5b6 100644 --- a/packages/bundler-rspack/src/build/types.ts +++ b/packages/bundler-rspack/src/build/types.ts @@ -29,7 +29,7 @@ export type FileMetaType = '' | 'font' | 'image' | 'script' | 'style' export type ModuleFilesMetaMap = Record /** - * Client manifest that collected from webpack stats + * Client manifest that collected from rspack stats */ export interface ClientManifest { all: string[] diff --git a/packages/bundler-rspack/src/config/handleDevtool.ts b/packages/bundler-rspack/src/config/handleDevtool.ts index cba5dfe73e..8e16791ef6 100644 --- a/packages/bundler-rspack/src/config/handleDevtool.ts +++ b/packages/bundler-rspack/src/config/handleDevtool.ts @@ -2,7 +2,7 @@ import type { App } from '@vuepress/core' import type { RspackChain } from 'rspack-chain' /** - * Set webpack devtool + * Set rspack devtool */ export const handleDevtool = ({ app, diff --git a/packages/bundler-rspack/src/config/handleModuleAssets.ts b/packages/bundler-rspack/src/config/handleModuleAssets.ts index fe53170a09..deaa25bcad 100644 --- a/packages/bundler-rspack/src/config/handleModuleAssets.ts +++ b/packages/bundler-rspack/src/config/handleModuleAssets.ts @@ -1,7 +1,7 @@ import type { RspackChain } from 'rspack-chain' /** - * Set webpack config to handle assets files + * Set rspack config to handle assets files */ export const handleModuleAssets = ({ config, diff --git a/packages/bundler-rspack/src/config/handleModuleJs.ts b/packages/bundler-rspack/src/config/handleModuleJs.ts index 41a41f5f1d..1d51c93fd7 100644 --- a/packages/bundler-rspack/src/config/handleModuleJs.ts +++ b/packages/bundler-rspack/src/config/handleModuleJs.ts @@ -8,7 +8,7 @@ import { resolveEsbuildLoaderOptions } from './resolveEsbuildLoaderOptions.js' const require = createRequire(import.meta.url) /** - * Set webpack module to handle js files + * Set rspack module to handle js files */ export const handleModuleJs = ({ options, diff --git a/packages/bundler-rspack/src/config/handleModulePug.ts b/packages/bundler-rspack/src/config/handleModulePug.ts index f145b33ead..b5a4bb7f34 100644 --- a/packages/bundler-rspack/src/config/handleModulePug.ts +++ b/packages/bundler-rspack/src/config/handleModulePug.ts @@ -1,7 +1,7 @@ import type { RspackChain } from 'rspack-chain' /** - * Set webpack module to handle pug files + * Set rspack module to handle pug files */ export const handleModulePug = ({ config }: { config: RspackChain }): void => { config.module diff --git a/packages/bundler-rspack/src/config/handleModuleStyles.ts b/packages/bundler-rspack/src/config/handleModuleStyles.ts index 63f000272a..f12bc1d474 100644 --- a/packages/bundler-rspack/src/config/handleModuleStyles.ts +++ b/packages/bundler-rspack/src/config/handleModuleStyles.ts @@ -12,7 +12,7 @@ import type { const require = createRequire(import.meta.url) /** - * Set webpack module to handle style files + * Set rspack module to handle style files */ export const handleModuleStyles = ({ options, diff --git a/packages/bundler-rspack/src/config/handleModuleTs.ts b/packages/bundler-rspack/src/config/handleModuleTs.ts index 03b7baa21e..5d2822027f 100644 --- a/packages/bundler-rspack/src/config/handleModuleTs.ts +++ b/packages/bundler-rspack/src/config/handleModuleTs.ts @@ -7,7 +7,7 @@ import { resolveEsbuildLoaderOptions } from './resolveEsbuildLoaderOptions.js' const require = createRequire(import.meta.url) /** - * Set webpack module to handle ts files + * Set rspack module to handle ts files */ export const handleModuleTs = ({ config }: { config: RspackChain }): void => { config.module diff --git a/packages/bundler-rspack/src/config/handleModuleVue.ts b/packages/bundler-rspack/src/config/handleModuleVue.ts index 11296ef7bb..d2d6d072d5 100644 --- a/packages/bundler-rspack/src/config/handleModuleVue.ts +++ b/packages/bundler-rspack/src/config/handleModuleVue.ts @@ -11,7 +11,7 @@ import type { RspackBundlerOptions } from '../types.js' const require = createRequire(import.meta.url) /** - * Set webpack module to handle vue files + * Set rspack module to handle vue files */ export const handleModuleVue = ({ app, diff --git a/packages/bundler-rspack/src/config/handleNode.ts b/packages/bundler-rspack/src/config/handleNode.ts index ca28423052..878960b123 100644 --- a/packages/bundler-rspack/src/config/handleNode.ts +++ b/packages/bundler-rspack/src/config/handleNode.ts @@ -1,7 +1,7 @@ import type { RspackChain } from 'rspack-chain' /** - * Set webpack node config + * Set rspack node config */ export const handleNode = ({ config }: { config: RspackChain }): void => { // do not polyfill or mock node globals and modules diff --git a/packages/bundler-rspack/src/config/handleOtherOptions.ts b/packages/bundler-rspack/src/config/handleOtherOptions.ts index 179f633f04..9e3a75d29f 100644 --- a/packages/bundler-rspack/src/config/handleOtherOptions.ts +++ b/packages/bundler-rspack/src/config/handleOtherOptions.ts @@ -44,8 +44,9 @@ export const handleOtherOptions = ({ ).version, 'vue-loader': (require('vue-loader/package.json') as { version: string }) .version, - 'webpack': (require('webpack/package.json') as { version: string }) - .version, + '@rspack/core': ( + require('@rspack/core/package.json') as { version: string } + ).version, }), }) } diff --git a/packages/bundler-rspack/src/dev/createDevConfig.ts b/packages/bundler-rspack/src/dev/createDevConfig.ts index 8b9b125c47..71a715bada 100644 --- a/packages/bundler-rspack/src/dev/createDevConfig.ts +++ b/packages/bundler-rspack/src/dev/createDevConfig.ts @@ -1,6 +1,5 @@ -import { HotModuleReplacementPlugin } from '@rspack/core' +import { HotModuleReplacementPlugin, HtmlRspackPlugin } from '@rspack/core' import type { App } from '@vuepress/core' -import HtmlPlugin from 'html-webpack-plugin' import type { RspackChain } from 'rspack-chain' import { createClientBaseConfig } from '../config/index.js' @@ -16,7 +15,7 @@ export const createDevConfig = async ( isBuild: false, }) - config.plugin('html').use(HtmlPlugin, [ + config.plugin('html').use(HtmlRspackPlugin, [ { template: app.options.templateDev, }, diff --git a/packages/bundler-rspack/src/dev/createDevServerConfig.ts b/packages/bundler-rspack/src/dev/createDevServerConfig.ts index 5ed3dd25bb..d8cc27ca56 100644 --- a/packages/bundler-rspack/src/dev/createDevServerConfig.ts +++ b/packages/bundler-rspack/src/dev/createDevServerConfig.ts @@ -1,8 +1,8 @@ import { sep } from 'node:path' +import type { Configuration, RspackDevServer } from '@rspack/dev-server' import type { App } from '@vuepress/core' import { path } from '@vuepress/utils' -import type WebpackDevServer from 'webpack-dev-server' import type { RspackBundlerOptions } from '../types.js' import { trailingSlashMiddleware } from './trailingSlashMiddleware.js' @@ -10,7 +10,7 @@ import { trailingSlashMiddleware } from './trailingSlashMiddleware.js' export const createDevServerConfig = ( app: App, options: RspackBundlerOptions, -): WebpackDevServer.Configuration => ({ +): Configuration => ({ allowedHosts: 'all', compress: true, devMiddleware: { @@ -27,7 +27,7 @@ export const createDevServerConfig = ( }, host: app.options.host, hot: true, - setupMiddlewares: (middlewares, devServer) => { + setupMiddlewares: (middlewares, devServer: RspackDevServer) => { devServer.app?.use(trailingSlashMiddleware) return ( options.devServerSetupMiddlewares?.(middlewares, devServer) ?? middlewares diff --git a/packages/bundler-rspack/src/dev/dev.ts b/packages/bundler-rspack/src/dev/dev.ts index 1797f9e950..83cdaaf5ca 100644 --- a/packages/bundler-rspack/src/dev/dev.ts +++ b/packages/bundler-rspack/src/dev/dev.ts @@ -1,7 +1,7 @@ +import { rspack } from '@rspack/core' +import { RspackDevServer } from '@rspack/dev-server' import type { App, Bundler } from '@vuepress/core' import { colors, logger, ora } from '@vuepress/utils' -import webpack from 'webpack' -import WebpackDevServer from 'webpack-dev-server' import { resolveRspackConfig } from '../resolveRspackConfig.js' import type { RspackBundlerOptions } from '../types.js' @@ -9,7 +9,7 @@ import { createDevConfig } from './createDevConfig.js' import { createDevServerConfig } from './createDevServerConfig.js' /** - * Create the dev method of webpack bundler + * Create the dev method of rspack bundler */ export const dev = async ( options: RspackBundlerOptions, @@ -18,26 +18,26 @@ export const dev = async ( // plugin hook: extendsBundlerOptions await app.pluginApi.hooks.extendsBundlerOptions.process(options, app) - // create webpack config - const webpackConfig = resolveRspackConfig({ + // create rspack config + const rspackConfig = resolveRspackConfig({ config: await createDevConfig(app, options), options, isServer: false, isBuild: false, }) - // create webpack compiler - const compiler = webpack(webpackConfig) + // create rspack compiler + const compiler = rspack(rspackConfig) - // create webpack-dev-server + // create rspack-dev-server const serverConfig = createDevServerConfig(app, options) - const server = new WebpackDevServer(serverConfig, compiler) + const server = new RspackDevServer(serverConfig, compiler) const [, close] = await Promise.all([ - // wait for webpack-dev-server to start + // wait for rspack-dev-server to start server.start(), - // wait for webpack compilation to complete + // wait for rspack compilation to complete new Promise<() => Promise>((resolve, reject) => { // create spinner const spinner = ora() @@ -49,7 +49,7 @@ export const dev = async ( if (hasStarted) return hasStarted = true - spinner.start('Compiling with webpack...') + spinner.start('Compiling with rspack...') }) // stop spinner, show compilation time and print url after first compilation @@ -57,14 +57,18 @@ export const dev = async ( if (hasFinished) return hasFinished = true - spinner.succeed(`Compilation finished in ${endTime - startTime}ms`) + spinner.succeed( + endTime && startTime + ? `Compilation finished in ${endTime - startTime}ms` + : 'Compilation finished', + ) // replace `0.0.0.0` with `localhost` as `0.0.0.0` is not available on windows const url = `http://${ serverConfig.host === '0.0.0.0' ? 'localhost' : serverConfig.host }:${serverConfig.port}${app.options.base}` logger.success( - `VuePress webpack dev server is listening at ${colors.cyan(url)}`, + `VuePress rspack dev server is listening at ${colors.cyan(url)}`, ) // resolve the close function diff --git a/packages/bundler-rspack/src/dev/trailingSlashMiddleware.ts b/packages/bundler-rspack/src/dev/trailingSlashMiddleware.ts index 34d34e0717..d99d677717 100644 --- a/packages/bundler-rspack/src/dev/trailingSlashMiddleware.ts +++ b/packages/bundler-rspack/src/dev/trailingSlashMiddleware.ts @@ -1,19 +1,31 @@ -import type { RequestHandler } from 'express' +import type { NextHandleFunction } from 'connect-next' + +const FAKE_HOST = 'http://.' /** * A middleware to add trailing slash to the url * * It will redirect '/foo' to '/foo/' with 302 */ -export const trailingSlashMiddleware: RequestHandler = (req, res, next) => { +export const trailingSlashMiddleware: NextHandleFunction = (req, res, next) => { if ( + !req.method || + !req.url || // only add trailing slash in GET and HEAD requests - !['GET', 'HEAD'].includes(req.method) || + !['GET', 'HEAD'].includes(req.method) + ) { + next() + return + } + + const { pathname } = new URL(req.url, FAKE_HOST) + + if ( // if the last section of the path has a dot, we think it has extension // and should not add trailing slash - req.path.split('/').pop()?.includes('.') || + pathname.split('/').pop()?.includes('.') || // if the path already has trailing slash - req.path.endsWith('/') + pathname.endsWith('/') ) { next() return @@ -21,6 +33,9 @@ export const trailingSlashMiddleware: RequestHandler = (req, res, next) => { // add trailing slash and retain query // notice that we should not use 301 in dev-server - const query = req.url.slice(req.path.length) - res.redirect(302, `${req.path}/${query}`) + const query = req.url.slice(pathname.length) + + res.statusCode = 302 + res.setHeader('Location', `${pathname}/${query}`) + res.end() } diff --git a/packages/bundler-rspack/src/loaders/vuepressMarkdownLoader.ts b/packages/bundler-rspack/src/loaders/vuepressMarkdownLoader.ts index 0b9251468a..28941f48a2 100644 --- a/packages/bundler-rspack/src/loaders/vuepressMarkdownLoader.ts +++ b/packages/bundler-rspack/src/loaders/vuepressMarkdownLoader.ts @@ -1,12 +1,12 @@ +import type { LoaderDefinitionFunction } from '@rspack/core' import type { App } from '@vuepress/core' -import type { LoaderDefinitionFunction } from 'webpack' export interface VuepressMarkdownLoaderOptions { app: App } /** - * A webpack loader to transform markdown content to vue component + * A rspack loader to transform markdown content to vue component */ export const vuepressMarkdownLoader: LoaderDefinitionFunction = async function vuepressMarkdownLoader(source) { diff --git a/packages/bundler-rspack/src/loaders/vuepressSsrLoader.ts b/packages/bundler-rspack/src/loaders/vuepressSsrLoader.ts index 65ac64e175..e1b83c28d7 100644 --- a/packages/bundler-rspack/src/loaders/vuepressSsrLoader.ts +++ b/packages/bundler-rspack/src/loaders/vuepressSsrLoader.ts @@ -1,7 +1,7 @@ -import type { LoaderDefinitionFunction } from 'webpack' +import type { LoaderDefinitionFunction } from '@rspack/core' /** - * A webpack loader to handle SSR dependencies + * A rspack loader to handle SSR dependencies * * This loader will only take effect in server bundle * because we only replace `ssrRender` code diff --git a/packages/bundler-rspack/src/types.ts b/packages/bundler-rspack/src/types.ts index 32338014ad..e5f6e71476 100644 --- a/packages/bundler-rspack/src/types.ts +++ b/packages/bundler-rspack/src/types.ts @@ -76,7 +76,7 @@ export interface RspackBundlerOptions extends BundlerOptions { } /** - * Common options for style preprocessor webpack loaders + * Common options for style preprocessor rspack loaders */ export interface StylePreprocessorLoaderOptions { additionalData?: @@ -86,7 +86,6 @@ export interface StylePreprocessorLoaderOptions { loaderContext: LoaderContext>, ) => string) sourceMap?: boolean - webpackImporter?: boolean } /** diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index be6e96f0c7..60da81ecd0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -157,9 +157,6 @@ importers: '@rspack/dev-server': specifier: ^2.0.1 version: 2.0.1(@rspack/core@2.0.3)(selfsigned@5.5.0) - '@types/express': - specifier: ^4.17.25 - version: 4.17.25 '@vuepress/bundlerutils': specifier: workspace:* version: link:../bundlerutils @@ -184,12 +181,6 @@ importers: esbuild-loader: specifier: ~4.4.3 version: 4.4.3(webpack@5.106.2(esbuild@0.28.0)) - express: - specifier: ^4.22.1 - version: 4.22.1 - html-webpack-plugin: - specifier: ^5.6.7 - version: 5.6.7(@rspack/core@2.0.3)(webpack@5.106.2(esbuild@0.28.0)) postcss: specifier: ^8.5.14 version: 8.5.14 @@ -214,6 +205,10 @@ importers: vue-router: specifier: catalog:vue version: 5.0.6(@vue/compiler-sfc@3.5.34)(vue@3.5.34(typescript@6.0.3)) + devDependencies: + connect-next: + specifier: ^4.0.1 + version: 4.0.1 packages/bundler-vite: dependencies: @@ -307,7 +302,7 @@ importers: version: 4.22.1 html-webpack-plugin: specifier: ^5.6.7 - version: 5.6.7(@rspack/core@2.0.3)(webpack@5.106.2(esbuild@0.28.0)) + version: 5.6.7(webpack@5.106.2(esbuild@0.28.0)) lightningcss: specifier: ^1.32.0 version: 1.32.0 @@ -2849,6 +2844,10 @@ packages: resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} engines: {node: '>=0.8'} + connect-next@4.0.1: + resolution: {integrity: sha512-nkHJWto78sXAooScrgvRt9E9omtwHBUTjCWRgxe3NbwNVC9cW4Lu0il0m2O867pgzJV66YXi2tXtSPtZy3Zmeg==} + engines: {node: ^20.19.0 || >=22.12.0} + constantinople@4.0.1: resolution: {integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==} @@ -8214,6 +8213,8 @@ snapshots: connect-history-api-fallback@2.0.0: {} + connect-next@4.0.1: {} + constantinople@4.0.1: dependencies: '@babel/parser': 7.29.3 @@ -9094,7 +9095,7 @@ snapshots: relateurl: 0.2.7 terser: 5.46.2 - html-webpack-plugin@5.6.7(@rspack/core@2.0.3)(webpack@5.106.2(esbuild@0.28.0)): + html-webpack-plugin@5.6.7(webpack@5.106.2(esbuild@0.28.0)): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -9102,7 +9103,6 @@ snapshots: pretty-error: 4.0.0 tapable: 2.3.3 optionalDependencies: - '@rspack/core': 2.0.3 webpack: 5.106.2(esbuild@0.28.0) htmlparser2@6.1.0: From 7719482e87ae05fd64abfa3ede70dd0995c31f6b Mon Sep 17 00:00:00 2001 From: "Mr.Hope" Date: Thu, 14 May 2026 17:44:30 +0800 Subject: [PATCH 04/13] fix: tweaks --- e2e/docs/.vuepress/config.ts | 19 ++++--- e2e/package.json | 5 ++ .../src/config/handleModuleJs.ts | 14 ++--- .../src/config/handleModuleTs.ts | 18 ++----- .../src/config/resolveEsbuildLoaderOptions.ts | 23 -------- .../src/config/resolveSwcLoaderOptions.ts | 52 +++++++++++++++++++ packages/vuepress/package.json | 4 ++ pnpm-lock.yaml | 6 +++ 8 files changed, 88 insertions(+), 53 deletions(-) delete mode 100644 packages/bundler-rspack/src/config/resolveEsbuildLoaderOptions.ts create mode 100644 packages/bundler-rspack/src/config/resolveSwcLoaderOptions.ts diff --git a/e2e/docs/.vuepress/config.ts b/e2e/docs/.vuepress/config.ts index f1ab1ad360..f87e8298c3 100644 --- a/e2e/docs/.vuepress/config.ts +++ b/e2e/docs/.vuepress/config.ts @@ -1,5 +1,6 @@ import process from 'node:process' +import { rspackBundler } from '@vuepress/bundler-rspack' import { viteBundler } from '@vuepress/bundler-vite' import { webpackBundler } from '@vuepress/bundler-webpack' import { defineUserConfig } from 'vuepress' @@ -62,15 +63,17 @@ export default defineUserConfig({ }, bundler: - E2E_BUNDLER === 'webpack' - ? webpackBundler() - : viteBundler({ - viteOptions: { - optimizeDeps: { - include: ['@vuepress-e2e/conditional-exports'], + E2E_BUNDLER === 'rspack' + ? rspackBundler() + : E2E_BUNDLER === 'webpack' + ? webpackBundler() + : viteBundler({ + viteOptions: { + optimizeDeps: { + include: ['@vuepress-e2e/conditional-exports'], + }, }, - }, - }), + }), theme: e2eTheme(), diff --git a/e2e/package.json b/e2e/package.json index ada316e14a..6a559f9c6e 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -5,19 +5,24 @@ "type": "module", "scripts": { "docs:build": "vuepress build docs --clean-cache --clean-temp", + "docs:build:rspack": "cross-env E2E_BUNDLER=rspack pnpm docs:build", "docs:build:webpack": "cross-env E2E_BUNDLER=webpack pnpm docs:build", "docs:clean": "rimraf docs/.vuepress/.temp docs/.vuepress/.cache docs/.vuepress/dist", "docs:dev": "vuepress dev docs --clean-cache --clean-temp", + "docs:dev:rspack": "cross-env E2E_BUNDLER=rspack pnpm docs:dev", "docs:dev:webpack": "cross-env E2E_BUNDLER=webpack pnpm docs:dev", "docs:serve": "serve -l 9080 docs/.vuepress/dist", "e2e:build": "cross-env E2E_COMMAND=build playwright test", + "e2e:build:rspack": "cross-env E2E_COMMAND=build E2E_BUNDLER=rspack playwright test", "e2e:build:webpack": "cross-env E2E_COMMAND=build E2E_BUNDLER=webpack playwright test", "e2e:dev": "cross-env E2E_COMMAND=dev playwright test", + "e2e:dev:rspack": "cross-env E2E_COMMAND=dev E2E_BUNDLER=rspack playwright test", "e2e:dev:webpack": "cross-env E2E_COMMAND=dev E2E_BUNDLER=webpack playwright test" }, "dependencies": { "@vuepress-e2e/conditional-exports": "file:./modules/conditional-exports", "@vuepress-e2e/style-exports": "file:./modules/style-exports", + "@vuepress/bundler-rspack": "workspace:*", "@vuepress/bundler-vite": "workspace:*", "@vuepress/bundler-webpack": "workspace:*", "sass": "^1.99.0", diff --git a/packages/bundler-rspack/src/config/handleModuleJs.ts b/packages/bundler-rspack/src/config/handleModuleJs.ts index 1d51c93fd7..afd19f4a99 100644 --- a/packages/bundler-rspack/src/config/handleModuleJs.ts +++ b/packages/bundler-rspack/src/config/handleModuleJs.ts @@ -1,11 +1,7 @@ -import { createRequire } from 'node:module' - import type { RspackChain } from 'rspack-chain' import type { RspackBundlerOptions } from '../types.js' -import { resolveEsbuildLoaderOptions } from './resolveEsbuildLoaderOptions.js' - -const require = createRequire(import.meta.url) +import { resolveSwcLoaderOptions } from './resolveSwcLoaderOptions.js' /** * Set rspack module to handle js files @@ -50,9 +46,9 @@ export const handleModuleJs = ({ return filePath.includes('node_modules') }) .end() - // use esbuild-loader - .use('esbuild-loader') - .loader(require.resolve('esbuild-loader')) - .options(resolveEsbuildLoaderOptions()) + // use swc-loader + .use('swc-loader') + .loader('builtin:swc-loader') + .options(resolveSwcLoaderOptions()) .end() } diff --git a/packages/bundler-rspack/src/config/handleModuleTs.ts b/packages/bundler-rspack/src/config/handleModuleTs.ts index 5d2822027f..5f4b672192 100644 --- a/packages/bundler-rspack/src/config/handleModuleTs.ts +++ b/packages/bundler-rspack/src/config/handleModuleTs.ts @@ -1,10 +1,6 @@ -import { createRequire } from 'node:module' - import type { RspackChain } from 'rspack-chain' -import { resolveEsbuildLoaderOptions } from './resolveEsbuildLoaderOptions.js' - -const require = createRequire(import.meta.url) +import { resolveSwcLoaderOptions } from './resolveSwcLoaderOptions.js' /** * Set rspack module to handle ts files @@ -13,13 +9,9 @@ export const handleModuleTs = ({ config }: { config: RspackChain }): void => { config.module .rule('ts') .test(/\.tsx?/) - // use esbuild-loader - .use('esbuild-loader') - .loader(require.resolve('esbuild-loader')) - .options( - resolveEsbuildLoaderOptions({ - loader: 'tsx', - }), - ) + // use swc-loader + .use('swc-loader') + .loader('builtin:swc-loader') + .options(resolveSwcLoaderOptions({}, true)) .end() } diff --git a/packages/bundler-rspack/src/config/resolveEsbuildLoaderOptions.ts b/packages/bundler-rspack/src/config/resolveEsbuildLoaderOptions.ts deleted file mode 100644 index 21ea899db0..0000000000 --- a/packages/bundler-rspack/src/config/resolveEsbuildLoaderOptions.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { EsbuildPluginOptions } from 'esbuild-loader' - -export const resolveEsbuildLoaderOptions = ( - options: EsbuildPluginOptions = {}, -): EsbuildPluginOptions => ({ - /** - * keep consistent with vite - * - * @see https://vite.dev/config/build-options.html#build-target - */ - target: ['es2023', 'chrome111', 'edge111', 'firefox114', 'safari16.4'], - - /** - * jsx options - */ - jsxFactory: 'jsx', - jsxFragment: 'Fragment', - - /** - * overrides - */ - ...options, -}) diff --git a/packages/bundler-rspack/src/config/resolveSwcLoaderOptions.ts b/packages/bundler-rspack/src/config/resolveSwcLoaderOptions.ts new file mode 100644 index 0000000000..b6debb3dc4 --- /dev/null +++ b/packages/bundler-rspack/src/config/resolveSwcLoaderOptions.ts @@ -0,0 +1,52 @@ +import type { SwcLoaderJscConfig, SwcLoaderOptions } from '@rspack/core' + +export const resolveSwcLoaderOptions = ( + options: SwcLoaderOptions = {}, + isTypescript = false, +): SwcLoaderOptions => ({ + env: { + /** + * keep consistent with vite + * + * @see https://vite.dev/config/build-options.html#build-target + */ + targets: { + chrome: '111', + edge: '111', + firefox: '114', + safari: '16.4', + }, + ...options.env, + }, + + jsc: { + parser: isTypescript + ? { + syntax: 'typescript', + tsx: true, + ...options.jsc?.parser, + } + : { + syntax: 'ecmascript', + jsx: true, + ...options.jsc?.parser, + }, + + transform: { + react: { + runtime: 'classic', + pragma: 'jsx', + pragmaFrag: 'Fragment', + development: false, + ...options.jsc?.transform?.react, + }, + ...options.jsc?.transform, + }, + ...(options.jsc as SwcLoaderJscConfig), + }, + + /** + * overrides + */ + ...options, +}) diff --git a/packages/vuepress/package.json b/packages/vuepress/package.json index ba45fe1c17..471b5d3bab 100644 --- a/packages/vuepress/package.json +++ b/packages/vuepress/package.json @@ -59,6 +59,7 @@ "vue": "catalog:vue" }, "peerDependencies": { + "@vuepress/bundler-rspack": "workspace:*", "@vuepress/bundler-vite": "workspace:*", "@vuepress/bundler-webpack": "workspace:*", "vue": "catalog:vue" @@ -67,6 +68,9 @@ "@vuepress/bundler-vite": { "optional": true }, + "@vuepress/bundler-rspack": { + "optional": true + }, "@vuepress/bundler-webpack": { "optional": true } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 60da81ecd0..f25dea138c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -114,6 +114,9 @@ importers: '@vuepress-e2e/style-exports': specifier: file:./modules/style-exports version: file:e2e/modules/style-exports + '@vuepress/bundler-rspack': + specifier: workspace:* + version: link:../packages/bundler-rspack '@vuepress/bundler-vite': specifier: workspace:* version: link:../packages/bundler-vite @@ -530,6 +533,9 @@ importers: packages/vuepress: dependencies: + '@vuepress/bundler-rspack': + specifier: workspace:* + version: link:../bundler-rspack '@vuepress/bundler-vite': specifier: workspace:* version: link:../bundler-vite From 224aaf3f5308569d20e099ac1632291141785c7e Mon Sep 17 00:00:00 2001 From: "Mr.Hope" Date: Thu, 14 May 2026 17:49:36 +0800 Subject: [PATCH 05/13] ci: add rspack e2e test --- .github/workflows/e2e.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index e50862dc93..1002d2234e 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -20,7 +20,7 @@ jobs: matrix: os: [ubuntu-latest, windows-latest, macos-latest] node: ['22', '24'] - bundler: ['webpack', 'vite'] + bundler: ['rspack', 'webpack', 'vite'] runs-on: ${{ matrix.os }} From 5837e171939ec899e9a9acb526391dac29cd8e22 Mon Sep 17 00:00:00 2001 From: "Mr.Hope" Date: Thu, 14 May 2026 17:53:23 +0800 Subject: [PATCH 06/13] chore: tweaks --- packages/bundler-rspack/package.json | 1 - .../src/config/handleModulePug.ts | 4 +- pnpm-lock.yaml | 287 ------------------ 3 files changed, 2 insertions(+), 290 deletions(-) diff --git a/packages/bundler-rspack/package.json b/packages/bundler-rspack/package.json index 4535aa5868..3fd3ae538e 100644 --- a/packages/bundler-rspack/package.json +++ b/packages/bundler-rspack/package.json @@ -41,7 +41,6 @@ "clean": "rimraf dist" }, "dependencies": { - "@rsbuild/plugin-pug": "^1.3.3", "@rspack/core": "^2.0.3", "@rspack/dev-server": "^2.0.1", "@vuepress/bundlerutils": "workspace:*", diff --git a/packages/bundler-rspack/src/config/handleModulePug.ts b/packages/bundler-rspack/src/config/handleModulePug.ts index b5a4bb7f34..e410f6469d 100644 --- a/packages/bundler-rspack/src/config/handleModulePug.ts +++ b/packages/bundler-rspack/src/config/handleModulePug.ts @@ -7,6 +7,6 @@ export const handleModulePug = ({ config }: { config: RspackChain }): void => { config.module .rule('pug') .test(/\.pug$/) - .use('pug-loader') - .loader('@rsbuild/plugin-pug') + .use('pug-plain-loader') + .loader('pug-plain-loader') } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f25dea138c..245bf416fc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -151,9 +151,6 @@ importers: packages/bundler-rspack: dependencies: - '@rsbuild/plugin-pug': - specifier: ^1.3.3 - version: 1.3.3 '@rspack/core': specifier: ^2.0.3 version: 2.0.3 @@ -1842,14 +1839,6 @@ packages: '@rolldown/pluginutils@1.0.0-rc.18': resolution: {integrity: sha512-CUY5Mnhe64xQBGZEEXQ5WyZwsc1JU3vAZLIxtrsBt3LO6UOb+C8GunVKqe9sT8NeWb4lqSaoJtp2xo6GxT1MNw==} - '@rsbuild/plugin-pug@1.3.3': - resolution: {integrity: sha512-shNzKSXhZm+yGB2KYOGIAi7MOxe566oKgONbILh53k9wpT9h6OFZWo5cGm33JZ8Y8HCc199WtxaE0U2Jy6zj/w==} - peerDependencies: - '@rsbuild/core': ^1.0.0 || ^2.0.0 - peerDependenciesMeta: - '@rsbuild/core': - optional: true - '@rspack/binding-darwin-arm64@2.0.3': resolution: {integrity: sha512-4UyCjLJwU/WxR6K1/gG4u3+jUsoaRHJ5rNu9fto/UbvrItwdlVNULChAApqZFw6mcSetMddSjSICeuj5pSB6sA==} cpu: [arm64] @@ -2075,9 +2064,6 @@ packages: '@types/picomatch@4.0.3': resolution: {integrity: sha512-iG0T6+nYJ9FAPmx9SsUlnwcq1ZVRuCXcVEvWnntoPlrOpwtSTKNDC9uVAxTsC3PUvJ+99n4RpAcNgBbHX3JSnQ==} - '@types/pug@2.0.10': - resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==} - '@types/qs@6.15.1': resolution: {integrity: sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==} @@ -2470,11 +2456,6 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@7.4.1: - resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} - engines: {node: '>=0.4.0'} - hasBin: true - acorn@8.16.0: resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} @@ -2562,16 +2543,10 @@ packages: array-ify@1.0.0: resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} - asap@2.0.6: - resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} - asn1js@3.0.10: resolution: {integrity: sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==} engines: {node: '>=12.0.0'} - assert-never@1.4.0: - resolution: {integrity: sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==} - assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -2595,10 +2570,6 @@ packages: peerDependencies: postcss: ^8.1.0 - babel-walk@3.0.0-canary-5: - resolution: {integrity: sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==} - engines: {node: '>= 10.0.0'} - balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -2736,9 +2707,6 @@ packages: character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} - character-parser@2.2.0: - resolution: {integrity: sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==} - chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -2854,9 +2822,6 @@ packages: resolution: {integrity: sha512-nkHJWto78sXAooScrgvRt9E9omtwHBUTjCWRgxe3NbwNVC9cW4Lu0il0m2O867pgzJV66YXi2tXtSPtZy3Zmeg==} engines: {node: ^20.19.0 || >=22.12.0} - constantinople@4.0.1: - resolution: {integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==} - content-disposition@0.5.2: resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==} engines: {node: '>= 0.6'} @@ -3119,9 +3084,6 @@ packages: resolution: {integrity: sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==} engines: {node: '>=6'} - doctypes@1.1.0: - resolution: {integrity: sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==} - dom-converter@0.2.0: resolution: {integrity: sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==} @@ -3641,10 +3603,6 @@ packages: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - hash-sum@2.0.0: resolution: {integrity: sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==} @@ -3793,10 +3751,6 @@ packages: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} - is-core-module@2.16.2: - resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} - engines: {node: '>= 0.4'} - is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} @@ -3807,9 +3761,6 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} hasBin: true - is-expression@4.0.0: - resolution: {integrity: sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==} - is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} engines: {node: '>=0.10.0'} @@ -3867,13 +3818,6 @@ packages: resolution: {integrity: sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - is-promise@2.2.2: - resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} - - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -3939,9 +3883,6 @@ packages: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true - js-stringify@1.0.2: - resolution: {integrity: sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==} - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3988,9 +3929,6 @@ packages: jsonfile@6.2.1: resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} - jstransformer@1.0.0: - resolution: {integrity: sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==} - katex@0.16.45: resolution: {integrity: sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==} hasBin: true @@ -4477,10 +4415,6 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} @@ -4577,9 +4511,6 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-scurry@2.0.2: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} @@ -4868,49 +4799,10 @@ packages: process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - promise@7.3.1: - resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==} - proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} - pug-attrs@3.0.0: - resolution: {integrity: sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==} - - pug-code-gen@3.0.4: - resolution: {integrity: sha512-6okWYIKdasTyXICyEtvobmTZAVX57JkzgzIi4iRJlin8kmhG+Xry2dsus+Mun/nGCn6F2U49haHI5mkELXB14g==} - - pug-error@2.1.0: - resolution: {integrity: sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==} - - pug-filters@4.0.0: - resolution: {integrity: sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==} - - pug-lexer@5.0.1: - resolution: {integrity: sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==} - - pug-linker@4.0.0: - resolution: {integrity: sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==} - - pug-load@3.0.0: - resolution: {integrity: sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==} - - pug-parser@6.0.0: - resolution: {integrity: sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==} - - pug-runtime@3.0.1: - resolution: {integrity: sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==} - - pug-strip-comments@2.0.0: - resolution: {integrity: sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==} - - pug-walk@2.0.0: - resolution: {integrity: sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==} - - pug@3.0.4: - resolution: {integrity: sha512-kFfq5mMzrS7+wrl5pLJzZEzemx34OQ0w4SARfhy/3yxTlhbstsudDwJzhf1hP02yHzbjoVMSXUj/Sz6RNfMyXg==} - punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} @@ -4975,9 +4867,6 @@ packages: resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} engines: {node: '>= 20.19.0'} - reduce-configs@1.1.2: - resolution: {integrity: sha512-AgBP55V8FC7NaqoOP2RCbTpu6LE+YuX3LUZkNAoitcfyS3/PIC8Obg/TJrBzTkJ+lDvZv0TTAeDpLkzjTtYlbw==} - reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} @@ -5017,11 +4906,6 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve@1.22.12: - resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} - engines: {node: '>= 0.4'} - hasBin: true - restore-cursor@5.1.0: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} engines: {node: '>=18'} @@ -5469,10 +5353,6 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - svgo@4.0.1: resolution: {integrity: sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==} engines: {node: '>=16'} @@ -5555,9 +5435,6 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - token-stream@1.0.0: - resolution: {integrity: sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==} - tree-dump@1.1.0: resolution: {integrity: sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==} engines: {node: '>=10.0'} @@ -5817,10 +5694,6 @@ packages: jsdom: optional: true - void-elements@3.1.0: - resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} - engines: {node: '>=0.10.0'} - vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} @@ -5954,10 +5827,6 @@ packages: wildcard@2.0.1: resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} - with@7.0.2: - resolution: {integrity: sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==} - engines: {node: '>= 10.0.0'} - word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -7134,13 +7003,6 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.18': {} - '@rsbuild/plugin-pug@1.3.3': - dependencies: - '@types/pug': 2.0.10 - lodash: 4.18.1 - pug: 3.0.4 - reduce-configs: 1.1.2 - '@rspack/binding-darwin-arm64@2.0.3': optional: true @@ -7358,8 +7220,6 @@ snapshots: '@types/picomatch@4.0.3': {} - '@types/pug@2.0.10': {} - '@types/qs@6.15.1': {} '@types/range-parser@1.2.7': {} @@ -7840,8 +7700,6 @@ snapshots: dependencies: acorn: 8.16.0 - acorn@7.4.1: {} - acorn@8.16.0: {} ajv-formats@2.1.1(ajv@8.20.0): @@ -7919,16 +7777,12 @@ snapshots: array-ify@1.0.0: {} - asap@2.0.6: {} - asn1js@3.0.10: dependencies: pvtsutils: 1.3.6 pvutils: 1.1.5 tslib: 2.8.1 - assert-never@1.4.0: {} - assertion-error@2.0.1: {} ast-kit@2.2.0: @@ -7956,10 +7810,6 @@ snapshots: postcss: 8.5.14 postcss-value-parser: 4.2.0 - babel-walk@3.0.0-canary-5: - dependencies: - '@babel/types': 7.29.0 - balanced-match@1.0.2: {} balanced-match@4.0.4: {} @@ -8105,10 +7955,6 @@ snapshots: character-entities@2.0.2: {} - character-parser@2.2.0: - dependencies: - is-regex: 1.2.1 - chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -8221,11 +8067,6 @@ snapshots: connect-next@4.0.1: {} - constantinople@4.0.1: - dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - content-disposition@0.5.2: {} content-disposition@0.5.4: @@ -8481,8 +8322,6 @@ snapshots: dependencies: '@leichtgewicht/ip-codec': 2.0.5 - doctypes@1.1.0: {} - dom-converter@0.2.0: dependencies: utila: 0.4.0 @@ -9062,10 +8901,6 @@ snapshots: has-symbols@1.1.0: {} - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - hash-sum@2.0.0: {} hasown@2.0.3: @@ -9205,19 +9040,10 @@ snapshots: dependencies: binary-extensions: 2.3.0 - is-core-module@2.16.2: - dependencies: - hasown: 2.0.3 - is-docker@2.2.1: {} is-docker@3.0.0: {} - is-expression@4.0.0: - dependencies: - acorn: 7.4.1 - object-assign: 4.1.1 - is-extendable@0.1.1: {} is-extglob@2.1.1: {} @@ -9254,15 +9080,6 @@ snapshots: is-port-reachable@4.0.0: {} - is-promise@2.2.2: {} - - is-regex@1.2.1: - dependencies: - call-bound: 1.0.4 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.3 - is-stream@2.0.1: {} is-unicode-supported@2.1.0: {} @@ -9325,8 +9142,6 @@ snapshots: jiti@2.7.0: {} - js-stringify@1.0.2: {} - js-tokens@4.0.0: {} js-yaml@3.14.2: @@ -9366,11 +9181,6 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 - jstransformer@1.0.0: - dependencies: - is-promise: 2.2.2 - promise: 7.3.1 - katex@0.16.45: dependencies: commander: 8.3.0 @@ -10028,8 +9838,6 @@ snapshots: dependencies: boolbase: 1.0.0 - object-assign@4.1.1: {} - object-inspect@1.13.4: {} obuf@1.1.2: {} @@ -10156,8 +9964,6 @@ snapshots: path-key@3.1.1: {} - path-parse@1.0.7: {} - path-scurry@2.0.2: dependencies: lru-cache: 11.3.6 @@ -10424,82 +10230,11 @@ snapshots: process-nextick-args@2.0.1: {} - promise@7.3.1: - dependencies: - asap: 2.0.6 - proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 ipaddr.js: 1.9.1 - pug-attrs@3.0.0: - dependencies: - constantinople: 4.0.1 - js-stringify: 1.0.2 - pug-runtime: 3.0.1 - - pug-code-gen@3.0.4: - dependencies: - constantinople: 4.0.1 - doctypes: 1.1.0 - js-stringify: 1.0.2 - pug-attrs: 3.0.0 - pug-error: 2.1.0 - pug-runtime: 3.0.1 - void-elements: 3.1.0 - with: 7.0.2 - - pug-error@2.1.0: {} - - pug-filters@4.0.0: - dependencies: - constantinople: 4.0.1 - jstransformer: 1.0.0 - pug-error: 2.1.0 - pug-walk: 2.0.0 - resolve: 1.22.12 - - pug-lexer@5.0.1: - dependencies: - character-parser: 2.2.0 - is-expression: 4.0.0 - pug-error: 2.1.0 - - pug-linker@4.0.0: - dependencies: - pug-error: 2.1.0 - pug-walk: 2.0.0 - - pug-load@3.0.0: - dependencies: - object-assign: 4.1.1 - pug-walk: 2.0.0 - - pug-parser@6.0.0: - dependencies: - pug-error: 2.1.0 - token-stream: 1.0.0 - - pug-runtime@3.0.1: {} - - pug-strip-comments@2.0.0: - dependencies: - pug-error: 2.1.0 - - pug-walk@2.0.0: {} - - pug@3.0.4: - dependencies: - pug-code-gen: 3.0.4 - pug-filters: 4.0.0 - pug-lexer: 5.0.1 - pug-linker: 4.0.0 - pug-load: 3.0.0 - pug-parser: 6.0.0 - pug-runtime: 3.0.1 - pug-strip-comments: 2.0.0 - punycode.js@2.3.1: {} punycode@2.3.1: {} @@ -10564,8 +10299,6 @@ snapshots: readdirp@5.0.0: {} - reduce-configs@1.1.2: {} - reflect-metadata@0.2.2: {} registry-auth-token@3.3.2: @@ -10599,13 +10332,6 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve@1.22.12: - dependencies: - es-errors: 1.3.0 - is-core-module: 2.16.2 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - restore-cursor@5.1.0: dependencies: onetime: 7.0.0 @@ -11082,8 +10808,6 @@ snapshots: dependencies: has-flag: 4.0.0 - supports-preserve-symlinks-flag@1.0.0: {} - svgo@4.0.1: dependencies: commander: 11.1.0 @@ -11164,8 +10888,6 @@ snapshots: toidentifier@1.0.1: {} - token-stream@1.0.0: {} - tree-dump@1.1.0(tslib@2.8.1): dependencies: tslib: 2.8.1 @@ -11405,8 +11127,6 @@ snapshots: transitivePeerDependencies: - msw - void-elements@3.1.0: {} - vscode-uri@3.1.0: {} vue-eslint-parser@10.4.0(eslint@10.3.0(jiti@2.7.0)): @@ -11602,13 +11322,6 @@ snapshots: wildcard@2.0.1: {} - with@7.0.2: - dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - assert-never: 1.4.0 - babel-walk: 3.0.0-canary-5 - word-wrap@1.2.5: {} wordwrap@1.0.0: {} From 9205c5eb723cacbf9e7b4254af78aedb27f4016a Mon Sep 17 00:00:00 2001 From: "Mr.Hope" Date: Thu, 14 May 2026 17:56:58 +0800 Subject: [PATCH 07/13] chore: tweaks --- packages/bundler-rspack/src/config/handleModule.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bundler-rspack/src/config/handleModule.ts b/packages/bundler-rspack/src/config/handleModule.ts index d5fb28689d..675d4ec854 100644 --- a/packages/bundler-rspack/src/config/handleModule.ts +++ b/packages/bundler-rspack/src/config/handleModule.ts @@ -26,7 +26,7 @@ export const handleModule = ({ isServer: boolean }): void => { // noParse - config.module.noParse(/(^(vue|vue-router)$)|(^@vue\/[^/]*$)/) + config.module.noParse(/^(?:vue|vue-router|(?:@vue\/[^/]+))$/) // vue files handleModuleVue({ app, options, config, isBuild, isServer }) From 86538d29e63e1be9f37028af1e5debf0ba8bdc77 Mon Sep 17 00:00:00 2001 From: "Mr.Hope" Date: Thu, 14 May 2026 19:22:33 +0800 Subject: [PATCH 08/13] fix: fix rspack build --- .../src/build/createClientPlugin.ts | 17 +++++++++++------ .../src/config/handleModuleStyles.ts | 3 ++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/bundler-rspack/src/build/createClientPlugin.ts b/packages/bundler-rspack/src/build/createClientPlugin.ts index 1af2b7ddd5..adc1a895aa 100644 --- a/packages/bundler-rspack/src/build/createClientPlugin.ts +++ b/packages/bundler-rspack/src/build/createClientPlugin.ts @@ -22,20 +22,25 @@ export const createClientPlugin = ( async (compilation) => { // get rspack stats object const { - assets = [], modules = [], entrypoints = {}, chunks = [], - } = compilation.getStats().toJson() + } = compilation.getStats().toJson({ + all: false, + modules: true, + entrypoints: true, + chunks: true, + chunkModules: true, + }) - // get all files - const allFiles = assets.map((a) => a.name) + // get all js/css files from all chunks + const allFiles = chunks.flatMap((c) => c.files ?? []) // get initial entry files const initialFiles = Object.keys(entrypoints) .flatMap( - (name) => - entrypoints[name].assets?.map((item) => item.name) ?? [], + (entry) => + entrypoints[entry].assets?.map(({ name }) => name) ?? [], ) .filter((file) => isJS(file) || isCSS(file)) diff --git a/packages/bundler-rspack/src/config/handleModuleStyles.ts b/packages/bundler-rspack/src/config/handleModuleStyles.ts index f12bc1d474..802e76b1bf 100644 --- a/packages/bundler-rspack/src/config/handleModuleStyles.ts +++ b/packages/bundler-rspack/src/config/handleModuleStyles.ts @@ -36,7 +36,8 @@ export const handleModuleStyles = ({ loaderName?: string loaderOptions?: StylePreprocessorLoaderOptions }): void => { - const rule = config.module.rule(lang).test(test) + // override rspack's native CSS type so CssExtractRspackPlugin + css-loader can process it + const rule = config.module.rule(lang).test(test).type('javascript/auto') if (!isServer) { if (isBuild) { From 095dd1a56d2b94a1ee55a053f35938da0e5283e4 Mon Sep 17 00:00:00 2001 From: "Mr.Hope" Date: Thu, 14 May 2026 19:35:21 +0800 Subject: [PATCH 09/13] fix: fix rspack base e2e --- e2e/docs/.vuepress/config.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/e2e/docs/.vuepress/config.ts b/e2e/docs/.vuepress/config.ts index f87e8298c3..cc0aab330e 100644 --- a/e2e/docs/.vuepress/config.ts +++ b/e2e/docs/.vuepress/config.ts @@ -58,7 +58,8 @@ export default defineUserConfig({ markdown: { assets: { - absolutePathPrependBase: E2E_BUNDLER === 'webpack', + absolutePathPrependBase: + E2E_BUNDLER === 'webpack' || E2E_BUNDLER === 'rspack', }, }, From 7bc52560c328387df42214af206ac36390266339 Mon Sep 17 00:00:00 2001 From: "Mr.Hope" Date: Fri, 15 May 2026 13:30:22 +0800 Subject: [PATCH 10/13] fix: fix ai --- .../bundler-rspack/src/config/handleModuleVue.ts | 2 +- .../src/config/resolveSwcLoaderOptions.ts | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/bundler-rspack/src/config/handleModuleVue.ts b/packages/bundler-rspack/src/config/handleModuleVue.ts index d2d6d072d5..0b407eb14d 100644 --- a/packages/bundler-rspack/src/config/handleModuleVue.ts +++ b/packages/bundler-rspack/src/config/handleModuleVue.ts @@ -5,7 +5,7 @@ import type { RspackChain } from 'rspack-chain' import type { VueLoaderOptions } from 'vue-loader' import { VueLoaderPlugin } from 'vue-loader' -import type { VuepressMarkdownLoaderOptions } from '../loaders/vuepressMarkdownLoader' +import type { VuepressMarkdownLoaderOptions } from '../loaders/vuepressMarkdownLoader.js' import type { RspackBundlerOptions } from '../types.js' const require = createRequire(import.meta.url) diff --git a/packages/bundler-rspack/src/config/resolveSwcLoaderOptions.ts b/packages/bundler-rspack/src/config/resolveSwcLoaderOptions.ts index b6debb3dc4..c262f71125 100644 --- a/packages/bundler-rspack/src/config/resolveSwcLoaderOptions.ts +++ b/packages/bundler-rspack/src/config/resolveSwcLoaderOptions.ts @@ -1,7 +1,7 @@ import type { SwcLoaderJscConfig, SwcLoaderOptions } from '@rspack/core' export const resolveSwcLoaderOptions = ( - options: SwcLoaderOptions = {}, + { env, jsc = {}, ...rest }: SwcLoaderOptions = {}, isTypescript = false, ): SwcLoaderOptions => ({ env: { @@ -16,7 +16,7 @@ export const resolveSwcLoaderOptions = ( firefox: '114', safari: '16.4', }, - ...options.env, + ...env, }, jsc: { @@ -24,12 +24,12 @@ export const resolveSwcLoaderOptions = ( ? { syntax: 'typescript', tsx: true, - ...options.jsc?.parser, + ...jsc.parser, } : { syntax: 'ecmascript', jsx: true, - ...options.jsc?.parser, + ...jsc.parser, }, transform: { @@ -38,15 +38,15 @@ export const resolveSwcLoaderOptions = ( pragma: 'jsx', pragmaFrag: 'Fragment', development: false, - ...options.jsc?.transform?.react, + ...jsc.transform?.react, }, - ...options.jsc?.transform, + ...jsc.transform, }, - ...(options.jsc as SwcLoaderJscConfig), + ...(jsc as SwcLoaderJscConfig), }, /** * overrides */ - ...options, + ...rest, }) From cb78fd50630cb50ff180ab73cdc6b2fbd9719b68 Mon Sep 17 00:00:00 2001 From: Mister-Hope Date: Sat, 16 May 2026 13:59:40 +0800 Subject: [PATCH 11/13] fix(bundler-rspack): fix swc options --- .../src/config/resolveSwcLoaderOptions.ts | 87 ++++++++++--------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/packages/bundler-rspack/src/config/resolveSwcLoaderOptions.ts b/packages/bundler-rspack/src/config/resolveSwcLoaderOptions.ts index c262f71125..e74786ab3c 100644 --- a/packages/bundler-rspack/src/config/resolveSwcLoaderOptions.ts +++ b/packages/bundler-rspack/src/config/resolveSwcLoaderOptions.ts @@ -3,50 +3,55 @@ import type { SwcLoaderJscConfig, SwcLoaderOptions } from '@rspack/core' export const resolveSwcLoaderOptions = ( { env, jsc = {}, ...rest }: SwcLoaderOptions = {}, isTypescript = false, -): SwcLoaderOptions => ({ - env: { - /** - * keep consistent with vite - * - * @see https://vite.dev/config/build-options.html#build-target - */ - targets: { - chrome: '111', - edge: '111', - firefox: '114', - safari: '16.4', +): SwcLoaderOptions => { + const { parser = {}, transform = {}, ...jscRest } = jsc as SwcLoaderJscConfig + + return { + env: { + /** + * keep consistent with vite + * + * @see https://vite.dev/config/build-options.html#build-target + */ + targets: { + chrome: '111', + edge: '111', + firefox: '114', + safari: '16.4', + }, + ...env, }, - ...env, - }, - jsc: { - parser: isTypescript - ? { - syntax: 'typescript', - tsx: true, - ...jsc.parser, - } - : { - syntax: 'ecmascript', - jsx: true, - ...jsc.parser, - }, + jsc: { + parser: isTypescript + ? { + syntax: 'typescript', + tsx: true, + ...parser, + } + : { + syntax: 'ecmascript', + jsx: true, + ...parser, + }, - transform: { - react: { - runtime: 'classic', - pragma: 'jsx', - pragmaFrag: 'Fragment', - development: false, - ...jsc.transform?.react, + transform: { + ...transform, + react: { + runtime: 'classic', + pragma: 'jsx', + pragmaFrag: 'Fragment', + development: false, + ...transform.react, + }, }, - ...jsc.transform, + + ...jscRest, }, - ...(jsc as SwcLoaderJscConfig), - }, - /** - * overrides - */ - ...rest, -}) + /** + * overrides + */ + ...rest, + } +} From 6066e6a6d8432085acfd0cb832a41dc994623af9 Mon Sep 17 00:00:00 2001 From: Mister-Hope Date: Sat, 16 May 2026 14:00:33 +0800 Subject: [PATCH 12/13] chore: tweaks --- packages/bundler-rspack/package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/bundler-rspack/package.json b/packages/bundler-rspack/package.json index 3fd3ae538e..3bae23ed88 100644 --- a/packages/bundler-rspack/package.json +++ b/packages/bundler-rspack/package.json @@ -62,5 +62,8 @@ }, "devDependencies": { "connect-next": "^4.0.1" + }, + "engines": { + "node": "^22.18.0 || ^24.0.0 || ^26.0.0" } } From 829acf9709eb9fc093c816d7e120550c8fd15cc2 Mon Sep 17 00:00:00 2001 From: Mister-Hope Date: Sat, 16 May 2026 14:13:09 +0800 Subject: [PATCH 13/13] chore: tweaks --- packages/bundler-rspack/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bundler-rspack/package.json b/packages/bundler-rspack/package.json index 3bae23ed88..faedd71f1c 100644 --- a/packages/bundler-rspack/package.json +++ b/packages/bundler-rspack/package.json @@ -64,6 +64,6 @@ "connect-next": "^4.0.1" }, "engines": { - "node": "^22.18.0 || ^24.0.0 || ^26.0.0" + "node": "^22.18.0 || ^24 || >=26" } }