-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
feat(kit): support async constructor for adding plugins #33619
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
|
WalkthroughThis PR adds local type aliases Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20–30 minutes
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
@nuxt/kit
@nuxt/nitro-server
nuxt
@nuxt/rspack-builder
@nuxt/schema
@nuxt/vite-builder
@nuxt/webpack-builder
commit: |
CodSpeed Performance ReportMerging #33619 will not alter performanceComparing Summary
Footnotes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👌
(need to investigate lint failure)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
packages/kit/src/build.ts (2)
9-10: Consider renamingThenable<T>to avoid confusion.In JavaScript/TypeScript terminology, "thenable" typically refers to objects implementing a
.then()method (duck-typed promises), not a union ofT | Promise<T>. Consider usingMaybePromise<T>orAwaitable<T>for better clarity.Apply this diff to improve the type name:
-type Thenable<T> = T | Promise<T> +type MaybePromise<T> = T | Promise<T>Then update all usages of
ThenabletoMaybePromisethroughout the file.
157-209: Consider caching the plugin resolution result.The plugin factory is invoked twice—at line 171 in the
vite:extendhook and at line 200 in thevite:extendConfighook. Whilst dynamic imports are cached by the module system, if the factory creates new plugin instances or has side effects, these will occur twice. Consider caching the result after the first resolution to ensure consistent behaviour and avoid unnecessary work.export function addVitePlugin (pluginOrGetter: Arrayable<VitePlugin> | (() => Thenable<Arrayable<VitePlugin>>), options: ExtendConfigOptions = {}): void { const nuxt = useNuxt() if (options.dev === false && nuxt.options.dev) { return } if (options.build === false && nuxt.options.build) { return } + let cachedPlugin: VitePlugin[] | undefined + async function getPlugin() { + if (!cachedPlugin) { + cachedPlugin = toArray(typeof pluginOrGetter === 'function' ? await pluginOrGetter() : pluginOrGetter) + } + return cachedPlugin + } + let needsEnvInjection = false nuxt.hook('vite:extend', async ({ config }) => { config.plugins ||= [] - const plugin = toArray(typeof pluginOrGetter === 'function' ? await pluginOrGetter() : pluginOrGetter) + const plugin = await getPlugin() if (options.server !== false && options.client !== false) { const method: 'push' | 'unshift' = options?.prepend ? 'unshift' : 'push' config.plugins[method](...plugin) return } if (!config.environments?.ssr || !config.environments.client) { needsEnvInjection = true return } const environmentName = options.server === false ? 'client' : 'ssr' const pluginName = plugin.map(p => p.name).join('|') config.plugins.push({ name: `${pluginName}:wrapper`, enforce: options?.prepend ? 'pre' : 'post', applyToEnvironment (environment) { if (environment.name === environmentName) { return plugin } }, }) }) nuxt.hook('vite:extendConfig', async (config, env) => { if (!needsEnvInjection) { return } - const plugin = toArray(typeof pluginOrGetter === 'function' ? await pluginOrGetter() : pluginOrGetter) + const plugin = await getPlugin() const method: 'push' | 'unshift' = options?.prepend ? 'unshift' : 'push' if (env.isClient && options.server === false) { config.plugins } if (env.isServer && options.client === false) { config.plugins } }) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/kit/src/build.ts(10 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Follow standard TypeScript conventions and best practices
Files:
packages/kit/src/build.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx,js,jsx,vue}: Use clear, descriptive variable and function names
Add comments only to explain complex logic or non-obvious implementations
Keep functions focused and manageable (generally under 50 lines), and extract complex logic into separate domain-specific files
Remove code that is not used or needed
Use error handling patterns consistently
Files:
packages/kit/src/build.ts
🧠 Learnings (1)
📚 Learning: 2024-11-28T21:22:40.496Z
Learnt from: GalacticHypernova
Repo: nuxt/nuxt PR: 29661
File: packages/kit/src/template.ts:227-229
Timestamp: 2024-11-28T21:22:40.496Z
Learning: In `packages/kit/src/template.ts`, when updating the `EXTENSION_RE` regular expression for TypeScript configuration, avoid using patterns like `(\.\w+)+$` as they can result in catastrophic backtracking.
Applied to files:
packages/kit/src/build.ts
🧬 Code graph analysis (1)
packages/kit/src/build.ts (3)
packages/webpack/builder.d.ts (1)
builder(10-10)packages/kit/src/index.ts (9)
ExtendWebpackConfigOptions(23-23)extendViteConfig(22-22)ExtendViteConfigOptions(23-23)addWebpackPlugin(22-22)extendWebpackConfig(22-22)addRspackPlugin(22-22)extendRspackConfig(22-22)addVitePlugin(22-22)ExtendConfigOptions(23-23)packages/kit/src/utils.ts (1)
toArray(2-4)
🔇 Additional comments (5)
packages/kit/src/build.ts (5)
61-85: LGTM!The async/await pattern is correctly implemented for both server and client configuration mutations. The function properly awaits the callback result, enabling asynchronous plugin factories.
132-140: LGTM!The async factory pattern is correctly implemented. The function properly awaits the plugin getter when it's a function, enabling lazy loading of plugins via dynamic imports.
144-152: LGTM!The async factory pattern is correctly implemented and consistent with
addWebpackPlugin. The function properly enables lazy loading of Rspack plugins.
211-229: LGTM!The
AddBuildPluginFactoryinterface correctly reflects the async factory capability, and the implementation properly delegates to the respective plugin-adding functions.
107-127: The implicit promise return is correct and properly awaited by the hook system.The hook handler at line 126 correctly returns the promise from
fn(config)implicitly. Nuxt's hook system awaits all returned promises (as confirmed inpackages/vite/src/vite.tsline 262:await nuxt.callHook('vite:extend', ctx)), so there is no risk of race conditions.However, there is a stylistic inconsistency:
addVitePlugin()at line 168 uses an explicitasynckeyword for the samevite:extendhook, whilstextendViteConfig()returns the promise implicitly withoutasync. For consistency within the file, consider using the same pattern—either explicitasyncor implicit promise return—across both functions.
I think it's a common use case to install plugins lazily, imagine:
The current workaround is:
But this would defeat the point of the factory function to lazy load, as
would result in loading unnecessary code.
This PR makes those utility support async usages.
Not sure if there are any performance concerns on this tho.