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 }} 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/e2e/docs/.vuepress/config.ts b/e2e/docs/.vuepress/config.ts index d670adfb49..1ab2424092 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 { createPage, defineUserConfig } from 'vuepress' @@ -56,15 +57,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 d59f66beb0..4329b21b31 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.101.6", 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..faedd71f1c --- /dev/null +++ b/packages/bundler-rspack/package.json @@ -0,0 +1,69 @@ +{ + "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", + "@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", + "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" + }, + "devDependencies": { + "connect-next": "^4.0.1" + }, + "engines": { + "node": "^22.18.0 || ^24 || >=26" + } +} diff --git a/packages/bundler-rspack/src/build/build.ts b/packages/bundler-rspack/src/build/build.ts new file mode 100644 index 0000000000..cb6819f77b --- /dev/null +++ b/packages/bundler-rspack/src/build/build.ts @@ -0,0 +1,126 @@ +import { rspack } from '@rspack/core' +import type { MultiRspackOptions } from '@rspack/core' +import { + createPageChunkFilesMap, + createVueServerApp, + getSsrTemplate, +} from '@vuepress/bundlerutils' +import type { App, Bundler } from '@vuepress/core' +import { colors, debug, fs, logger, withSpinner } from '@vuepress/utils' + +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-rspack/build') + +export const build = async ( + options: RspackBundlerOptions, + app: App, +): ReturnType => { + // plugin hook: extendsBundlerOptions + await app.pluginApi.hooks.extendsBundlerOptions.process(options, app) + + // rspack compile + log('compiling start') + await withSpinner('Compiling with rspack')(async () => { + // create rspack 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) => { + rspack( + [clientConfig, serverConfig] as MultiRspackOptions, + (err, stats) => { + if (err) { + reject(err) + } else { + 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() + } + }, + ) + }) + }) + 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) + + // build page path -> chunk files map for preload & prefetch + const pageChunkFilesMap = createPageChunkFilesMap({ + pages: app.pages, + resolvePageChunkFiles: (page) => + clientManifest.chunks[page.chunkName] ?? [], + }) + + // 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, + pageChunkFilesMap, + }) + } + }) + + // 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..a4d9a509b9 --- /dev/null +++ b/packages/bundler-rspack/src/build/createClientConfig.ts @@ -0,0 +1,96 @@ +import { + CopyRspackPlugin, + CssExtractRspackPlugin, + LightningCssMinimizerRspackPlugin, +} from '@rspack/core' +import type { Module } from '@rspack/core' +import type { App } from '@vuepress/core' +import { fs } from '@vuepress/utils' +import type { RspackChain } from 'rspack-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..42ad628d8e --- /dev/null +++ b/packages/bundler-rspack/src/build/createClientPlugin.ts @@ -0,0 +1,127 @@ +import type { RspackPluginInstance, StatsModule } from '@rspack/core' +import { fs } from '@vuepress/utils' + +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 rspack bundled files info for SSR + */ +export const createClientPlugin = ( + outputFile: string, +): RspackPluginInstance => { + const clientPlugin: RspackPluginInstance = { + apply(compiler) { + compiler.hooks.emit.tapPromise( + 'vuepress-client-plugin', + async (compilation) => { + // get rspack stats object + const { + modules = [], + entrypoints = {}, + chunks = [], + } = compilation.getStats().toJson({ + all: false, + modules: true, + entrypoints: true, + chunks: true, + chunkModules: true, + }) + + // 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( + (entry) => + entrypoints[entry].assets?.map(({ name }) => 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 + }) + + // build chunk name -> output file names mapping + // chunk groups may contain more than one chunk (e.g. a js chunk + // and its extracted css chunk), so we collect files from the group + // to keep all files of a page together + const chunkFiles = Object.fromEntries( + Array.from(compilation.namedChunkGroups, ([name, chunkGroup]) => [ + name, + chunkGroup.getFiles(), + ]), + ) + + // generate client manifest json file + const clientManifest: ClientManifest = { + all: allFiles, + initial: initialFiles, + async: asyncFiles, + modules: manifestModules, + chunks: chunkFiles, + } + + 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..2eba869e0b --- /dev/null +++ b/packages/bundler-rspack/src/build/createServerConfig.ts @@ -0,0 +1,45 @@ +import type { App } from '@vuepress/core' +import type { RspackChain } from 'rspack-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) + .library({ type: '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..aedd9b98a0 --- /dev/null +++ b/packages/bundler-rspack/src/build/renderPage.ts @@ -0,0 +1,87 @@ +import type { PageChunkFilesMap, 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 RspackPageSSRContext 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, + pageChunkFilesMap, +}: { + app: App + page: Page + vueApp: VueApp + vueRouter: Router + ssrTemplate: string + initialFilesMeta: FileMeta[] + asyncFilesMeta: FileMeta[] + moduleFilesMetaMap: ModuleFilesMetaMap + pageChunkFilesMap: PageChunkFilesMap +}): 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, + page, + pageClientFilesMeta, + pageChunkFilesMap, + }), + 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..6172d9197c --- /dev/null +++ b/packages/bundler-rspack/src/build/renderPagePrefetchLinks.ts @@ -0,0 +1,67 @@ +import type { PageChunkFilesMap } from '@vuepress/bundlerutils' +import { resolveLinkedPageChunkFiles } from '@vuepress/bundlerutils' +import type { App, Page } from '@vuepress/core' + +import type { FileMeta } from './types.js' + +/** + * Render prefetch links of current page + */ +export const renderPagePrefetchLinks = ({ + app, + asyncFilesMeta, + page, + pageClientFilesMeta, + pageChunkFilesMap, +}: { + app: App + asyncFilesMeta: FileMeta[] + page: Page + pageClientFilesMeta: FileMeta[] + pageChunkFilesMap: PageChunkFilesMap +}): string => { + // shouldPrefetch option + const { shouldPrefetch } = app.options + + // do not render prefetch links + if (shouldPrefetch === false) { + return '' + } + + let prefetchFilesMeta: FileMeta[] + + if (shouldPrefetch === 'as-needed') { + const linkedPageChunkFiles = resolveLinkedPageChunkFiles({ + base: app.options.base, + page, + pageChunkFilesMap, + }) + + // async files excluding files used by current page + // filtered to only linked pages' chunk files + prefetchFilesMeta = asyncFilesMeta.filter( + ({ file }) => + linkedPageChunkFiles.has(file) && + !pageClientFilesMeta.some((f) => f.file === file), + ) + } else { + // async files excluding files used by current page should be prefetch + 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 !== 'as-needed' && + !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..98240f6095 --- /dev/null +++ b/packages/bundler-rspack/src/build/types.ts @@ -0,0 +1,43 @@ +/** + * 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 rspack stats + */ +export interface ClientManifest { + all: string[] + initial: string[] + async: string[] + modules: Record + /** + * Chunk name to output file names mapping + */ + chunks: 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..8e16791ef6 --- /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 rspack 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..675d4ec854 --- /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..deaa25bcad --- /dev/null +++ b/packages/bundler-rspack/src/config/handleModuleAssets.ts @@ -0,0 +1,48 @@ +import type { RspackChain } from 'rspack-chain' + +/** + * Set rspack 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..afd19f4a99 --- /dev/null +++ b/packages/bundler-rspack/src/config/handleModuleJs.ts @@ -0,0 +1,54 @@ +import type { RspackChain } from 'rspack-chain' + +import type { RspackBundlerOptions } from '../types.js' +import { resolveSwcLoaderOptions } from './resolveSwcLoaderOptions.js' + +/** + * Set rspack 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 swc-loader + .use('swc-loader') + .loader('builtin:swc-loader') + .options(resolveSwcLoaderOptions()) + .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..e410f6469d --- /dev/null +++ b/packages/bundler-rspack/src/config/handleModulePug.ts @@ -0,0 +1,12 @@ +import type { RspackChain } from 'rspack-chain' + +/** + * Set rspack 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..802e76b1bf --- /dev/null +++ b/packages/bundler-rspack/src/config/handleModuleStyles.ts @@ -0,0 +1,131 @@ +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 rspack 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 => { + // 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) { + 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..5f4b672192 --- /dev/null +++ b/packages/bundler-rspack/src/config/handleModuleTs.ts @@ -0,0 +1,17 @@ +import type { RspackChain } from 'rspack-chain' + +import { resolveSwcLoaderOptions } from './resolveSwcLoaderOptions.js' + +/** + * Set rspack module to handle ts files + */ +export const handleModuleTs = ({ config }: { config: RspackChain }): void => { + config.module + .rule('ts') + .test(/\.tsx?/) + // use swc-loader + .use('swc-loader') + .loader('builtin:swc-loader') + .options(resolveSwcLoaderOptions({}, true)) + .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..0b407eb14d --- /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.js' +import type { RspackBundlerOptions } from '../types.js' + +const require = createRequire(import.meta.url) + +/** + * Set rspack 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..878960b123 --- /dev/null +++ b/packages/bundler-rspack/src/config/handleNode.ts @@ -0,0 +1,12 @@ +import type { RspackChain } from 'rspack-chain' + +/** + * Set rspack 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..9e3a75d29f --- /dev/null +++ b/packages/bundler-rspack/src/config/handleOtherOptions.ts @@ -0,0 +1,52 @@ +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, + '@rspack/core': ( + require('@rspack/core/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/resolveSwcLoaderOptions.ts b/packages/bundler-rspack/src/config/resolveSwcLoaderOptions.ts new file mode 100644 index 0000000000..e74786ab3c --- /dev/null +++ b/packages/bundler-rspack/src/config/resolveSwcLoaderOptions.ts @@ -0,0 +1,57 @@ +import type { SwcLoaderJscConfig, SwcLoaderOptions } from '@rspack/core' + +export const resolveSwcLoaderOptions = ( + { env, jsc = {}, ...rest }: SwcLoaderOptions = {}, + isTypescript = false, +): 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, + }, + + jsc: { + parser: isTypescript + ? { + syntax: 'typescript', + tsx: true, + ...parser, + } + : { + syntax: 'ecmascript', + jsx: true, + ...parser, + }, + + transform: { + ...transform, + react: { + runtime: 'classic', + pragma: 'jsx', + pragmaFrag: 'Fragment', + development: false, + ...transform.react, + }, + }, + + ...jscRest, + }, + + /** + * overrides + */ + ...rest, + } +} diff --git a/packages/bundler-rspack/src/dev/createDevConfig.ts b/packages/bundler-rspack/src/dev/createDevConfig.ts new file mode 100644 index 0000000000..71a715bada --- /dev/null +++ b/packages/bundler-rspack/src/dev/createDevConfig.ts @@ -0,0 +1,27 @@ +import { HotModuleReplacementPlugin, HtmlRspackPlugin } from '@rspack/core' +import type { App } from '@vuepress/core' +import type { RspackChain } from 'rspack-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(HtmlRspackPlugin, [ + { + template: app.options.templateDev, + }, + ]) + + config.plugin('hmr').use(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..d8cc27ca56 --- /dev/null +++ b/packages/bundler-rspack/src/dev/createDevServerConfig.ts @@ -0,0 +1,50 @@ +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 { RspackBundlerOptions } from '../types.js' +import { trailingSlashMiddleware } from './trailingSlashMiddleware.js' + +export const createDevServerConfig = ( + app: App, + options: RspackBundlerOptions, +): 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: RspackDevServer) => { + 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..83cdaaf5ca --- /dev/null +++ b/packages/bundler-rspack/src/dev/dev.ts @@ -0,0 +1,91 @@ +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 { 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 rspack bundler + */ +export const dev = async ( + options: RspackBundlerOptions, + app: App, +): ReturnType => { + // plugin hook: extendsBundlerOptions + await app.pluginApi.hooks.extendsBundlerOptions.process(options, app) + + // create rspack config + const rspackConfig = resolveRspackConfig({ + config: await createDevConfig(app, options), + options, + isServer: false, + isBuild: false, + }) + + // create rspack compiler + const compiler = rspack(rspackConfig) + + // create rspack-dev-server + const serverConfig = createDevServerConfig(app, options) + const server = new RspackDevServer(serverConfig, compiler) + + const [, close] = await Promise.all([ + // wait for rspack-dev-server to start + server.start(), + + // wait for rspack 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 rspack...') + }) + + // 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( + 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 rspack 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..d99d677717 --- /dev/null +++ b/packages/bundler-rspack/src/dev/trailingSlashMiddleware.ts @@ -0,0 +1,41 @@ +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: NextHandleFunction = (req, res, next) => { + if ( + !req.method || + !req.url || + // only add trailing slash in GET and HEAD requests + !['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 + pathname.split('/').pop()?.includes('.') || + // if the path already has trailing slash + pathname.endsWith('/') + ) { + next() + return + } + + // add trailing slash and retain query + // notice that we should not use 301 in dev-server + const query = req.url.slice(pathname.length) + + res.statusCode = 302 + res.setHeader('Location', `${pathname}/${query}`) + res.end() +} diff --git a/packages/bundler-rspack/src/index.ts b/packages/bundler-rspack/src/index.ts new file mode 100644 index 0000000000..0042b3e5cc --- /dev/null +++ b/packages/bundler-rspack/src/index.ts @@ -0,0 +1,8 @@ +import { merge } from 'rspack-merge' + +import { rspackBundler } from './rspackBundler.js' + +export type * from './types.js' + +export { merge as rspackMergeConfig, rspackBundler } +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..28941f48a2 --- /dev/null +++ b/packages/bundler-rspack/src/loaders/vuepressMarkdownLoader.ts @@ -0,0 +1,39 @@ +import type { LoaderDefinitionFunction } from '@rspack/core' +import type { App } from '@vuepress/core' + +export interface VuepressMarkdownLoaderOptions { + app: App +} + +/** + * A rspack 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..e1b83c28d7 --- /dev/null +++ b/packages/bundler-rspack/src/loaders/vuepressSsrLoader.ts @@ -0,0 +1,29 @@ +import type { LoaderDefinitionFunction } from '@rspack/core' + +/** + * A rspack 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..0a13b12cda --- /dev/null +++ b/packages/bundler-rspack/src/resolveRspackConfig.ts @@ -0,0 +1,36 @@ +import type { Configuration } from '@rspack/core' +import type { RspackChain } from 'rspack-chain' + +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 + let rspackConfig = config.toConfig() + + // allow modifying rspack config via `configureRspack` + const configureRspackResult = options.configureRspack?.( + rspackConfig, + isServer, + isBuild, + ) + + // if `configureRspack` returns a configuration object, use this object as the new rspack config + if (configureRspackResult) { + 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..5fa19e140c --- /dev/null +++ b/packages/bundler-rspack/src/rspackBundler.ts @@ -0,0 +1,14 @@ +import type { Bundler } from '@vuepress/core' +import { merge } from 'rspack-merge' + +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', + type: 'rspack', + dev: async (app) => dev(options, app), + build: async (app) => build(options, app), + mergeConfig: merge as Bundler['mergeConfig'], +}) diff --git a/packages/bundler-rspack/src/types.ts b/packages/bundler-rspack/src/types.ts new file mode 100644 index 0000000000..cb11b9b439 --- /dev/null +++ b/packages/bundler-rspack/src/types.ts @@ -0,0 +1,148 @@ +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 { + /** + * Edit the internal Rspack config. + * + * @param config - Rspack config + * @param isServer - Whether it is server bundle + * @param isBuild - Whether in build mode + * @returns if returns a configuration object, it will be used as the new rspack config, otherwise the original config object will be used + */ + 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 rspack loaders + */ +export interface StylePreprocessorLoaderOptions { + additionalData?: + | string + | (( + content: string, + loaderContext: LoaderContext>, + ) => string) + sourceMap?: 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/packages/core/src/app/resolveAppMarkdown.ts b/packages/core/src/app/resolveAppMarkdown.ts index 534509baa0..edba28970f 100644 --- a/packages/core/src/app/resolveAppMarkdown.ts +++ b/packages/core/src/app/resolveAppMarkdown.ts @@ -19,6 +19,7 @@ export const resolveAppMarkdown = async (app: App): Promise => { if (app.options.markdown.assets !== false) { app.options.markdown.assets ??= {} app.options.markdown.assets.absolutePathPrependBase ??= + app.options.bundler.type === 'rspack' || app.options.bundler.type === 'webpack' } diff --git a/packages/vuepress/package.json b/packages/vuepress/package.json index 0fc73578e0..df767f967d 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 b987601e86..41633d6771 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -117,6 +117,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 @@ -131,7 +134,7 @@ importers: version: 1.100.0 sass-loader: specifier: ^17.0.0 - version: 17.0.0(sass-embedded@1.100.0)(sass@1.101.6)(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) + version: 17.0.0(@rspack/core@2.2.2)(sass-embedded@1.100.0)(sass@1.101.6)(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) vue: specifier: catalog:vue version: 3.5.40(typescript@6.0.3) @@ -149,6 +152,67 @@ importers: specifier: ^14.2.6 version: 14.2.6(supports-color@8.1.1) + packages/bundler-rspack: + dependencies: + '@rspack/core': + specifier: ^2.0.3 + version: 2.2.2 + '@rspack/dev-server': + specifier: ^2.0.1 + version: 2.2.1(@rspack/core@2.2.2)(selfsigned@5.5.0) + '@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.4(postcss@8.5.22) + css-loader: + specifier: ^7.1.4 + version: 7.1.4(@rspack/core@2.2.2)(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) + esbuild-loader: + specifier: ~4.4.3 + version: 4.4.3(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) + postcss: + specifier: ^8.5.14 + version: 8.5.22 + postcss-loader: + specifier: ^8.2.1 + version: 8.2.1(@rspack/core@2.2.2)(postcss@8.5.22)(typescript@6.0.3)(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) + rspack-chain: + specifier: ^2.0.1 + version: 2.2.0(@rspack/core@2.2.2) + rspack-merge: + specifier: ^0.1.1 + version: 0.1.1 + style-loader: + specifier: ^4.0.0 + version: 4.0.0(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) + vue: + specifier: catalog:vue + version: 3.5.40(typescript@6.0.3) + vue-loader: + specifier: ^17.4.2 + version: 17.4.2(@vue/compiler-sfc@3.5.40)(vue@3.5.40(typescript@6.0.3))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) + vue-router: + specifier: catalog:vue + version: 5.2.0(@rspack/core@2.2.2)(@vue/compiler-sfc@3.5.40)(esbuild@0.28.1)(rolldown@1.2.0)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.6)(terser@5.49.0)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) + devDependencies: + connect-next: + specifier: ^4.0.1 + version: 4.0.3 + packages/bundler-vite: dependencies: '@vitejs/plugin-vue': @@ -192,7 +256,7 @@ importers: version: 3.5.40(typescript@6.0.3) vue-router: specifier: catalog:vue - version: 5.2.0(@vue/compiler-sfc@3.5.40)(esbuild@0.28.1)(rolldown@1.2.0)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.6)(terser@5.49.0)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) + version: 5.2.0(@rspack/core@2.2.2)(@vue/compiler-sfc@3.5.40)(esbuild@0.28.1)(rolldown@1.2.0)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.6)(terser@5.49.0)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) devDependencies: '@types/connect-history-api-fallback': specifier: ^1.5.4 @@ -229,7 +293,7 @@ importers: version: 14.0.0(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) css-loader: specifier: ^7.1.4 - version: 7.1.4(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) + version: 7.1.4(@rspack/core@2.2.2)(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) css-minimizer-webpack-plugin: specifier: ^8.0.0 version: 8.0.0(clean-css@5.3.3)(csso@5.0.5)(esbuild@0.28.1)(lightningcss@1.33.0)(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) @@ -253,7 +317,7 @@ importers: version: 8.5.22 postcss-loader: specifier: ^8.2.1 - version: 8.2.1(postcss@8.5.22)(typescript@6.0.3)(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) + version: 8.2.1(@rspack/core@2.2.2)(postcss@8.5.22)(typescript@6.0.3)(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) style-loader: specifier: ^4.0.0 version: 4.0.0(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) @@ -265,7 +329,7 @@ importers: version: 17.4.2(@vue/compiler-sfc@3.5.40)(vue@3.5.40(typescript@6.0.3))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) vue-router: specifier: catalog:vue - version: 5.2.0(@vue/compiler-sfc@3.5.40)(esbuild@0.28.1)(rolldown@1.2.0)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.6)(terser@5.49.0)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) + version: 5.2.0(@rspack/core@2.2.2)(@vue/compiler-sfc@3.5.40)(esbuild@0.28.1)(rolldown@1.2.0)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.6)(terser@5.49.0)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) webpack: specifier: ^5.108.4 version: 5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22) @@ -301,7 +365,7 @@ importers: version: 3.5.40(typescript@6.0.3) vue-router: specifier: catalog:vue - version: 5.2.0(@vue/compiler-sfc@3.5.40)(esbuild@0.28.1)(rolldown@1.2.0)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.6)(terser@5.49.0)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) + version: 5.2.0(@rspack/core@2.2.2)(@vue/compiler-sfc@3.5.40)(esbuild@0.28.1)(rolldown@1.2.0)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.6)(terser@5.49.0)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) packages/cli: dependencies: @@ -347,7 +411,7 @@ importers: version: 3.5.40(typescript@6.0.3) vue-router: specifier: catalog:vue - version: 5.2.0(@vue/compiler-sfc@3.5.40)(esbuild@0.28.1)(rolldown@1.2.0)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.6)(terser@5.49.0)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) + version: 5.2.0(@rspack/core@2.2.2)(@vue/compiler-sfc@3.5.40)(esbuild@0.28.1)(rolldown@1.2.0)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.6)(terser@5.49.0)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) packages/core: dependencies: @@ -468,6 +532,9 @@ importers: packages/vuepress: dependencies: + '@vuepress/bundler-rspack': + specifier: workspace:* + version: link:../bundler-rspack '@vuepress/bundler-vite': specifier: workspace:* version: link:../bundler-vite @@ -691,6 +758,9 @@ packages: '@emnapi/core@1.11.2': resolution: {integrity: sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==} + '@emnapi/core@1.11.3': + resolution: {integrity: sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==} + '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} @@ -700,165 +770,327 @@ packages: '@emnapi/runtime@1.11.2': resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==} + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} '@emnapi/wasi-threads@1.2.2': resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} + '@emnapi/wasi-threads@1.2.3': + resolution: {integrity: sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==} + '@epic-web/invariant@1.0.0': resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/aix-ppc64@0.28.1': resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.28.1': resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.28.1': resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.28.1': resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.28.1': resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.28.1': resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.28.1': resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.28.1': resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.28.1': resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.28.1': resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.28.1': resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.28.1': resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.28.1': resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-ppc64@0.28.1': resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-riscv64@0.28.1': resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.28.1': resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.28.1': resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-arm64@0.28.1': resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/netbsd-x64@0.28.1': resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-arm64@0.28.1': resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.28.1': resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/openharmony-arm64@0.28.1': resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.28.1': resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.28.1': resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.28.1': resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.28.1': resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} engines: {node: '>=18'} @@ -1615,6 +1847,117 @@ packages: '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + '@rspack/binding-darwin-arm64@2.2.2': + resolution: {integrity: sha512-/le/AvV4HSinXTPs2Lqpujxt189Z5T10Ggt96QzckLRPvIchzqoavVDDjltzC7XcaZ87XCH/X06jNKgzkcBBNA==} + cpu: [arm64] + os: [darwin] + + '@rspack/binding-darwin-x64@2.2.2': + resolution: {integrity: sha512-uFIcUPUXiPxM6ljenLafp5TemT8eLZm1riRn8fJYmpqNCK+aCcTaud18XHZpI5SjzzcY+xUHfVShgvNzKXuf2g==} + cpu: [x64] + os: [darwin] + + '@rspack/binding-linux-arm64-gnu@2.2.2': + resolution: {integrity: sha512-Pjby4pDSMNJQK2VBzpgCj6lb+DGuenS1fEDb6xi5/apbJb9v5WE+e43Mz7i+XqgXS8e846pjaONV3KM5WKB1LQ==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rspack/binding-linux-arm64-musl@2.2.2': + resolution: {integrity: sha512-0u9O7tTVT2z+F6o/eEY6f6+My8Jn9U56QiBwkfy90ZaoAfZyQSSTxqaK/zA7W43oFxQefeCpiPas27VUzrSakw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rspack/binding-linux-ppc64-gnu@2.2.2': + resolution: {integrity: sha512-N3lVnhq5qOvpmP5n386JzR1GcE8HzAqq4/r440Z6yle9m7PhVFJ6oXVWxgaDTYV0mtv9YLJmaG+YrjYfUa1vuA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rspack/binding-linux-riscv64-gnu@2.2.2': + resolution: {integrity: sha512-ReClZyp32/rJkUDV/oGDU0X6BCFyEkTR6r4stFwm/qOOaG6mUMRzZe4gur8Yh979p4Hiz9EdkmfEHY02GBXcaQ==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rspack/binding-linux-riscv64-musl@2.2.2': + resolution: {integrity: sha512-mqsorvTNerr3r8zI35NFTPYATPDlhepdiUhZjKT6ylqpHlP7vLU9fp4aEMK/CuTv2f+IVsa0+iZqtMxHs2tSjw==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rspack/binding-linux-s390x-gnu@2.2.2': + resolution: {integrity: sha512-ql2Jub8QYWSugBppmj2u0SjcIj6fOQuAaLCYQOqU7zbvz/uuWTfoqmdWKExwrxeCU9Tzt7emVM0ETuVEpoca+A==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rspack/binding-linux-x64-gnu@2.2.2': + resolution: {integrity: sha512-MNYKYEHrtIVEno2q5rgpou/JVffRwn109xPK3kxct95EojHsniNa8jwy6eEHeOazP4EN60Si7NElE3aQ6JssHw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rspack/binding-linux-x64-musl@2.2.2': + resolution: {integrity: sha512-y9/9CmE8lrECaF17GAhacibTL+SvlEPEotQnUuBFC/WFtXh8hU2E7a7bAkpYGSLH6kM0nrJZHO3hTvM1wdWOJw==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rspack/binding-wasm32-wasi@2.2.2': + resolution: {integrity: sha512-VbDIjjeFwZvMSKAOGY5IbU6lLzt6AHHHncTdMMkZ94Xk7O2BOHe9BXDV32Ln29TIW2C8m1fdxfPZWDiecVghUQ==} + cpu: [wasm32] + + '@rspack/binding-win32-arm64-msvc@2.2.2': + resolution: {integrity: sha512-rfcNg0W3ZPZvXma1gTyEt9/Z8FxASIaQr+sMWTSaTPPaeU3xY1+0hYcrD0kUFNs3/5L4u63myI4R8qRXiuW3pA==} + cpu: [arm64] + os: [win32] + + '@rspack/binding-win32-ia32-msvc@2.2.2': + resolution: {integrity: sha512-TFPvr9RZw9oHIhooDhXHzWjKcHpGPTxkznSeM2poIWU0CdEuua2rVUfsrriTF1Dmx+9kMly61DQmyOHCbb+b2g==} + cpu: [ia32] + os: [win32] + + '@rspack/binding-win32-x64-msvc@2.2.2': + resolution: {integrity: sha512-GvEGyL594dtWN9SoVnKWh0exrM8WLInaUjwcuA2JKbCi1ak/9iHxip/U1dY3DuVqBYBhmvYq96JPbl91xnzFjg==} + cpu: [x64] + os: [win32] + + '@rspack/binding@2.2.2': + resolution: {integrity: sha512-gWjKDQfVQJSBh/I+y9WTlyERsiShSJ7eI6Yl0SJs/6gjx8t4ixuwWCsaEFFjwSL4nSn6ML5hNQ7UFY3gj72BWA==} + + '@rspack/core@2.2.2': + resolution: {integrity: sha512-/yztfDZR5syIPBrUpzBpL+6fhhl0IHBPcXlNr4tOMBULbocFIz7Z4/cqvf1ix0DBbKpIGx99v6N1IDbk2gi8hw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@module-federation/runtime-tools': ^0.24.1 || ^2.0.0 + '@swc/helpers': ^0.5.23 + peerDependenciesMeta: + '@module-federation/runtime-tools': + optional: true + '@swc/helpers': + optional: true + + '@rspack/dev-middleware@2.0.4': + resolution: {integrity: sha512-VCdT8hv9YvMPiBohhukD/OkGB+2GJ7mPRbeuDJ/jIT6hv5gvmJCnydMetJVARh6vXoBtfSHEd2gX78Dqaxh1NQ==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@rspack/core': ^2.0.0 + peerDependenciesMeta: + '@rspack/core': + optional: true + + '@rspack/dev-server@2.2.1': + resolution: {integrity: sha512-Il8HbYGK3rH5rM0XmUOsOGZVw69BKRpBZ61P28Fy8ry35CtfniDBWtbo/rvJtIT/sK0qwijmNrhF498ltsV+uA==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@rspack/core': ^2.0.0 + selfsigned: ^5.0.0 + peerDependenciesMeta: + selfsigned: + optional: true + '@simple-libs/child-process-utils@2.0.0': resolution: {integrity: sha512-dvNoRKLijXnD0XoJAz94pbNuB5GQgDr55UhpSPhffDkTT0Cmcqh9jSCOtwfT2d4H6MI9E7c4SgtMuJXZ6F3c6A==} engines: {node: '>=22'} @@ -2614,6 +2957,10 @@ packages: resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} engines: {node: '>=0.8'} + connect-next@4.0.3: + resolution: {integrity: sha512-XzXkWnwNtbFJEPqW9gWZBRsS83lbI+alSxSSOL8PbHDqzRG6CMxLOfNGrpFfwr6jx1SqmwLvdNHlMZRaa0z4Fw==} + engines: {node: ^20.19.0 || >=22.12.0} + content-disposition@0.5.2: resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==} engines: {node: '>= 0.6'} @@ -2993,11 +3340,21 @@ packages: es-toolkit@1.49.0: resolution: {integrity: sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==} + esbuild-loader@4.4.3: + resolution: {integrity: sha512-Wpui03EzqC151xFteKlgJQhbyZl5CgnBpUHXVuao02nItULlkaTeiLdEMPTmR2zdwpEBWkXVNoT5dDOYJluUzg==} + peerDependencies: + webpack: ^4.40.0 || ^5.0.0 + esbuild-loader@4.5.0: resolution: {integrity: sha512-rVYe97IN1+VoealVHQ3STEPbfTm+vvPk7AZPrL53Pt6JUGBhHTnIqyaow7EveMFlmQ2A1bLp7q19sP4PppaCDQ==} peerDependencies: webpack: ^4.40.0 || ^5.0.0 + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + esbuild@0.28.1: resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} engines: {node: '>=18'} @@ -4721,6 +5078,17 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + rspack-chain@2.2.0: + resolution: {integrity: sha512-5h/5duc5uZwygmuX0X41ROovPy358t2L0mvV55e9os6GEw1LnvbhzzHaps2VXu60oEByllVp0+0mKHcFD51fNQ==} + peerDependencies: + '@rspack/core': ^2.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'} @@ -5922,6 +6290,12 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/core@1.11.3': + dependencies: + '@emnapi/wasi-threads': 1.2.3 + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 @@ -5937,6 +6311,11 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/wasi-threads@1.2.1': dependencies: tslib: 2.8.1 @@ -5947,83 +6326,166 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/wasi-threads@1.2.3': + dependencies: + tslib: 2.8.1 + optional: true + '@epic-web/invariant@1.0.0': {} + '@esbuild/aix-ppc64@0.27.7': + optional: true + '@esbuild/aix-ppc64@0.28.1': optional: true + '@esbuild/android-arm64@0.27.7': + optional: true + '@esbuild/android-arm64@0.28.1': optional: true + '@esbuild/android-arm@0.27.7': + optional: true + '@esbuild/android-arm@0.28.1': optional: true + '@esbuild/android-x64@0.27.7': + optional: true + '@esbuild/android-x64@0.28.1': optional: true + '@esbuild/darwin-arm64@0.27.7': + optional: true + '@esbuild/darwin-arm64@0.28.1': optional: true + '@esbuild/darwin-x64@0.27.7': + optional: true + '@esbuild/darwin-x64@0.28.1': optional: true + '@esbuild/freebsd-arm64@0.27.7': + optional: true + '@esbuild/freebsd-arm64@0.28.1': optional: true + '@esbuild/freebsd-x64@0.27.7': + optional: true + '@esbuild/freebsd-x64@0.28.1': optional: true + '@esbuild/linux-arm64@0.27.7': + optional: true + '@esbuild/linux-arm64@0.28.1': optional: true + '@esbuild/linux-arm@0.27.7': + optional: true + '@esbuild/linux-arm@0.28.1': optional: true + '@esbuild/linux-ia32@0.27.7': + optional: true + '@esbuild/linux-ia32@0.28.1': optional: true + '@esbuild/linux-loong64@0.27.7': + optional: true + '@esbuild/linux-loong64@0.28.1': optional: true + '@esbuild/linux-mips64el@0.27.7': + optional: true + '@esbuild/linux-mips64el@0.28.1': optional: true + '@esbuild/linux-ppc64@0.27.7': + optional: true + '@esbuild/linux-ppc64@0.28.1': optional: true + '@esbuild/linux-riscv64@0.27.7': + optional: true + '@esbuild/linux-riscv64@0.28.1': optional: true + '@esbuild/linux-s390x@0.27.7': + optional: true + '@esbuild/linux-s390x@0.28.1': optional: true + '@esbuild/linux-x64@0.27.7': + optional: true + '@esbuild/linux-x64@0.28.1': optional: true + '@esbuild/netbsd-arm64@0.27.7': + optional: true + '@esbuild/netbsd-arm64@0.28.1': optional: true + '@esbuild/netbsd-x64@0.27.7': + optional: true + '@esbuild/netbsd-x64@0.28.1': optional: true + '@esbuild/openbsd-arm64@0.27.7': + optional: true + '@esbuild/openbsd-arm64@0.28.1': optional: true + '@esbuild/openbsd-x64@0.27.7': + optional: true + '@esbuild/openbsd-x64@0.28.1': optional: true + '@esbuild/openharmony-arm64@0.27.7': + optional: true + '@esbuild/openharmony-arm64@0.28.1': optional: true + '@esbuild/sunos-x64@0.27.7': + optional: true + '@esbuild/sunos-x64@0.28.1': optional: true + '@esbuild/win32-arm64@0.27.7': + optional: true + '@esbuild/win32-arm64@0.28.1': optional: true + '@esbuild/win32-ia32@0.27.7': + optional: true + '@esbuild/win32-ia32@0.28.1': optional: true + '@esbuild/win32-x64@0.27.7': + optional: true + '@esbuild/win32-x64@0.28.1': optional: true @@ -6372,6 +6834,13 @@ snapshots: '@tybys/wasm-util': 0.10.3 optional: true + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)': + dependencies: + '@emnapi/core': 1.11.3 + '@emnapi/runtime': 1.11.3 + '@tybys/wasm-util': 0.10.3 + optional: true + '@noble/hashes@1.4.0': {} '@ota-meshi/ast-token-store@0.3.0': {} @@ -6698,6 +7167,84 @@ snapshots: '@rolldown/pluginutils@1.0.1': {} + '@rspack/binding-darwin-arm64@2.2.2': + optional: true + + '@rspack/binding-darwin-x64@2.2.2': + optional: true + + '@rspack/binding-linux-arm64-gnu@2.2.2': + optional: true + + '@rspack/binding-linux-arm64-musl@2.2.2': + optional: true + + '@rspack/binding-linux-ppc64-gnu@2.2.2': + optional: true + + '@rspack/binding-linux-riscv64-gnu@2.2.2': + optional: true + + '@rspack/binding-linux-riscv64-musl@2.2.2': + optional: true + + '@rspack/binding-linux-s390x-gnu@2.2.2': + optional: true + + '@rspack/binding-linux-x64-gnu@2.2.2': + optional: true + + '@rspack/binding-linux-x64-musl@2.2.2': + optional: true + + '@rspack/binding-wasm32-wasi@2.2.2': + dependencies: + '@emnapi/core': 1.11.3 + '@emnapi/runtime': 1.11.3 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + optional: true + + '@rspack/binding-win32-arm64-msvc@2.2.2': + optional: true + + '@rspack/binding-win32-ia32-msvc@2.2.2': + optional: true + + '@rspack/binding-win32-x64-msvc@2.2.2': + optional: true + + '@rspack/binding@2.2.2': + optionalDependencies: + '@rspack/binding-darwin-arm64': 2.2.2 + '@rspack/binding-darwin-x64': 2.2.2 + '@rspack/binding-linux-arm64-gnu': 2.2.2 + '@rspack/binding-linux-arm64-musl': 2.2.2 + '@rspack/binding-linux-ppc64-gnu': 2.2.2 + '@rspack/binding-linux-riscv64-gnu': 2.2.2 + '@rspack/binding-linux-riscv64-musl': 2.2.2 + '@rspack/binding-linux-s390x-gnu': 2.2.2 + '@rspack/binding-linux-x64-gnu': 2.2.2 + '@rspack/binding-linux-x64-musl': 2.2.2 + '@rspack/binding-wasm32-wasi': 2.2.2 + '@rspack/binding-win32-arm64-msvc': 2.2.2 + '@rspack/binding-win32-ia32-msvc': 2.2.2 + '@rspack/binding-win32-x64-msvc': 2.2.2 + + '@rspack/core@2.2.2': + dependencies: + '@rspack/binding': 2.2.2 + + '@rspack/dev-middleware@2.0.4(@rspack/core@2.2.2)': + optionalDependencies: + '@rspack/core': 2.2.2 + + '@rspack/dev-server@2.2.1(@rspack/core@2.2.2)(selfsigned@5.5.0)': + dependencies: + '@rspack/core': 2.2.2 + '@rspack/dev-middleware': 2.0.4(@rspack/core@2.2.2) + optionalDependencies: + selfsigned: 5.5.0 + '@simple-libs/child-process-utils@2.0.0': dependencies: '@simple-libs/stream-utils': 2.0.0 @@ -7544,7 +8091,7 @@ snapshots: dependencies: ansi-align: 3.0.1 camelcase: 7.0.1 - chalk: 5.0.1 + chalk: 5.6.2 cli-boxes: 3.0.0 string-width: 5.1.2 type-fest: 2.19.0 @@ -7739,6 +8286,8 @@ snapshots: connect-history-api-fallback@2.0.0: {} + connect-next@4.0.3: {} + content-disposition@0.5.2: {} content-disposition@0.5.4: @@ -7833,7 +8382,7 @@ snapshots: dependencies: postcss: 8.5.22 - css-loader@7.1.4(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)): + css-loader@7.1.4(@rspack/core@2.2.2)(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)): dependencies: icss-utils: 5.1.0(postcss@8.5.22) postcss: 8.5.22 @@ -7844,6 +8393,7 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.8.5 optionalDependencies: + '@rspack/core': 2.2.2 webpack: 5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22) css-minimizer-webpack-plugin@8.0.0(clean-css@5.3.3)(csso@5.0.5)(esbuild@0.28.1)(lightningcss@1.33.0)(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)): @@ -8098,6 +8648,14 @@ snapshots: es-toolkit@1.49.0: {} + esbuild-loader@4.4.3(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)): + dependencies: + esbuild: 0.27.7 + get-tsconfig: 4.14.0 + loader-utils: 2.0.4 + webpack: 5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22) + webpack-sources: 3.5.1 + esbuild-loader@4.5.0(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)): dependencies: esbuild: 0.28.1 @@ -8106,6 +8664,35 @@ snapshots: webpack: 5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22) webpack-sources: 3.5.1 + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + esbuild@0.28.1: optionalDependencies: '@esbuild/aix-ppc64': 0.28.1 @@ -9658,13 +10245,14 @@ snapshots: postcss: 8.5.22 yaml: 2.9.0 - postcss-loader@8.2.1(postcss@8.5.22)(typescript@6.0.3)(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)): + postcss-loader@8.2.1(@rspack/core@2.2.2)(postcss@8.5.22)(typescript@6.0.3)(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)): dependencies: cosmiconfig: 9.0.2(typescript@6.0.3) jiti: 2.7.0 postcss: 8.5.22 semver: 7.8.5 optionalDependencies: + '@rspack/core': 2.2.2 webpack: 5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22) transitivePeerDependencies: - typescript @@ -9993,6 +10581,12 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.2.0 '@rolldown/binding-win32-x64-msvc': 1.2.0 + rspack-chain@2.2.0(@rspack/core@2.2.2): + optionalDependencies: + '@rspack/core': 2.2.2 + + rspack-merge@0.1.1: {} + run-applescript@7.1.0: {} rxjs@7.8.2: @@ -10092,8 +10686,9 @@ snapshots: sass-embedded-win32-arm64: 1.100.0 sass-embedded-win32-x64: 1.100.0 - sass-loader@17.0.0(sass-embedded@1.100.0)(sass@1.101.6)(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)): + sass-loader@17.0.0(@rspack/core@2.2.2)(sass-embedded@1.100.0)(sass@1.101.6)(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)): optionalDependencies: + '@rspack/core': 2.2.2 sass: 1.101.6 sass-embedded: 1.100.0 webpack: 5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22) @@ -10551,12 +11146,13 @@ snapshots: pathe: 2.0.3 picomatch: 4.0.5 - unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.0)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.6)(terser@5.49.0)(yaml@2.9.0))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)): + unplugin@3.3.0(@rspack/core@2.2.2)(esbuild@0.28.1)(rolldown@1.2.0)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.6)(terser@5.49.0)(yaml@2.9.0))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)): dependencies: '@jridgewell/remapping': 2.3.5 picomatch: 4.0.5 webpack-virtual-modules: 0.6.2 optionalDependencies: + '@rspack/core': 2.2.2 esbuild: 0.28.1 rolldown: 1.2.0 vite: 8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.6)(terser@5.49.0)(yaml@2.9.0) @@ -10689,7 +11285,7 @@ snapshots: '@vue/compiler-sfc': 3.5.40 vue: 3.5.40(typescript@6.0.3) - vue-router@5.2.0(@vue/compiler-sfc@3.5.40)(esbuild@0.28.1)(rolldown@1.2.0)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.6)(terser@5.49.0)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)): + vue-router@5.2.0(@rspack/core@2.2.2)(@vue/compiler-sfc@3.5.40)(esbuild@0.28.1)(rolldown@1.2.0)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.6)(terser@5.49.0)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)): dependencies: '@babel/generator': 8.0.0 '@vue-macros/common': 3.1.4(vue@3.5.40(typescript@6.0.3)) @@ -10706,7 +11302,7 @@ snapshots: picomatch: 4.0.5 scule: 1.3.0 tinyglobby: 0.2.17 - unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.2.0)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.6)(terser@5.49.0)(yaml@2.9.0))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) + unplugin: 3.3.0(@rspack/core@2.2.2)(esbuild@0.28.1)(rolldown@1.2.0)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.6)(terser@5.49.0)(yaml@2.9.0))(webpack@5.108.4(clean-css@5.3.3)(cssnano@7.1.9(postcss@8.5.22))(csso@5.0.5)(esbuild@0.28.1)(html-minifier-terser@6.1.0)(lightningcss@1.33.0)(postcss@8.5.22)) unplugin-utils: 0.3.2 vue: 3.5.40(typescript@6.0.3) yaml: 2.9.0