From 757a92f1c7c4fa961ed963edd245df77382dfde6 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Mon, 22 Aug 2022 17:51:13 +0800 Subject: [PATCH] feat: support object style hooks (#9634) --- package.json | 2 +- packages/plugin-vue/package.json | 2 +- packages/vite/package.json | 2 +- packages/vite/src/node/build.ts | 53 ++++++-- packages/vite/src/node/config.ts | 66 ++++++---- packages/vite/src/node/index.ts | 2 +- packages/vite/src/node/plugin.ts | 83 +++++++----- packages/vite/src/node/plugins/index.ts | 61 ++++++++- packages/vite/src/node/plugins/worker.ts | 1 - packages/vite/src/node/preview.ts | 8 +- packages/vite/src/node/server/hmr.ts | 10 +- packages/vite/src/node/server/index.ts | 6 +- .../vite/src/node/server/pluginContainer.ts | 104 ++++++++++----- playground/lib/__tests__/lib.spec.ts | 2 +- .../__tests__/object-hooks.spec.ts | 6 + playground/object-hooks/index.html | 4 + playground/object-hooks/main.ts | 2 + playground/object-hooks/package.json | 14 ++ playground/object-hooks/vite.config.ts | 69 ++++++++++ pnpm-lock.yaml | 124 +++++------------- 20 files changed, 398 insertions(+), 223 deletions(-) create mode 100644 playground/object-hooks/__tests__/object-hooks.spec.ts create mode 100644 playground/object-hooks/index.html create mode 100644 playground/object-hooks/main.ts create mode 100644 playground/object-hooks/package.json create mode 100644 playground/object-hooks/vite.config.ts diff --git a/package.json b/package.json index 487e722ffcbed7..f86b7e62058542 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "prettier": "2.7.1", "prompts": "^2.4.2", "rimraf": "^3.0.2", - "rollup": ">=2.75.6 <2.77.0 || ~2.77.0", + "rollup": "~2.78.0", "semver": "^7.3.7", "simple-git-hooks": "^2.8.0", "tslib": "^2.4.0", diff --git a/packages/plugin-vue/package.json b/packages/plugin-vue/package.json index 6d639acd8495f8..6a74e109625873 100644 --- a/packages/plugin-vue/package.json +++ b/packages/plugin-vue/package.json @@ -42,7 +42,7 @@ "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.15", "debug": "^4.3.4", - "rollup": ">=2.75.6 <2.77.0 || ~2.77.0", + "rollup": "~2.78.0", "slash": "^4.0.0", "source-map": "^0.6.1", "vite": "workspace:*", diff --git a/packages/vite/package.json b/packages/vite/package.json index 483a5c5c6e46b8..8ef093c103f8f1 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -61,7 +61,7 @@ "esbuild": "^0.14.47", "postcss": "^8.4.16", "resolve": "^1.22.1", - "rollup": ">=2.75.6 <2.77.0 || ~2.77.0" + "rollup": "~2.78.0" }, "optionalDependencies": { "fsevents": "~2.3.2" diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index c9d265036754e5..34d1bb98ea60fc 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -16,7 +16,6 @@ import type { WarningHandler, WatcherOptions } from 'rollup' -import type Rollup from 'rollup' import type { Terser } from 'types/terser' import commonjsPlugin from '@rollup/plugin-commonjs' import type { RollupCommonJSOptions } from 'types/commonjs' @@ -788,34 +787,60 @@ function injectSsrFlagToHooks(plugin: Plugin): Plugin { } } -function wrapSsrResolveId( - fn?: Rollup.ResolveIdHook -): Rollup.ResolveIdHook | undefined { - if (!fn) return +function wrapSsrResolveId(hook?: Plugin['resolveId']): Plugin['resolveId'] { + if (!hook) return - return function (id, importer, options) { + const fn = 'handler' in hook ? hook.handler : hook + const handler: Plugin['resolveId'] = function (id, importer, options) { return fn.call(this, id, importer, injectSsrFlag(options)) } + + if ('handler' in hook) { + return { + ...hook, + handler + } as Plugin['resolveId'] + } else { + return handler + } } -function wrapSsrLoad(fn?: Rollup.LoadHook): Rollup.LoadHook | undefined { - if (!fn) return +function wrapSsrLoad(hook?: Plugin['load']): Plugin['load'] { + if (!hook) return - return function (id, ...args) { + const fn = 'handler' in hook ? hook.handler : hook + const handler: Plugin['load'] = function (id, ...args) { // @ts-expect-error: Receiving options param to be future-proof if Rollup adds it return fn.call(this, id, injectSsrFlag(args[0])) } + + if ('handler' in hook) { + return { + ...hook, + handler + } as Plugin['load'] + } else { + return handler + } } -function wrapSsrTransform( - fn?: Rollup.TransformHook -): Rollup.TransformHook | undefined { - if (!fn) return +function wrapSsrTransform(hook?: Plugin['transform']): Plugin['transform'] { + if (!hook) return - return function (code, importer, ...args) { + const fn = 'handler' in hook ? hook.handler : hook + const handler: Plugin['transform'] = function (code, importer, ...args) { // @ts-expect-error: Receiving options param to be future-proof if Rollup adds it return fn.call(this, code, importer, injectSsrFlag(args[0])) } + + if ('handler' in hook) { + return { + ...hook, + handler + } as Plugin['transform'] + } else { + return handler + } } function injectSsrFlag>( diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index f29d06e27e29e2..4fb0fcc9a15a93 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -8,7 +8,7 @@ import type { Alias, AliasOptions } from 'types/alias' import aliasPlugin from '@rollup/plugin-alias' import { build } from 'esbuild' import type { RollupOptions } from 'rollup' -import type { Plugin } from './plugin' +import type { HookHandler, Plugin } from './plugin' import type { BuildOptions, RenderBuiltAssetUrl, @@ -33,7 +33,11 @@ import { normalizeAlias, normalizePath } from './utils' -import { resolvePlugins } from './plugins' +import { + createPluginHookUtils, + getSortedPluginsByHook, + resolvePlugins +} from './plugins' import type { ESBuildOptions } from './plugins/esbuild' import { CLIENT_ENTRY, @@ -289,7 +293,7 @@ export interface LegacyOptions { buildSsrCjsExternalHeuristics?: boolean } -export interface ResolveWorkerOptions { +export interface ResolveWorkerOptions extends PluginHookUtils { format: 'es' | 'iife' plugins: Plugin[] rollupOptions: RollupOptions @@ -334,9 +338,16 @@ export type ResolvedConfig = Readonly< worker: ResolveWorkerOptions appType: AppType experimental: ExperimentalOptions - } + } & PluginHookUtils > +export interface PluginHookUtils { + getSortedPlugins: (hookName: keyof Plugin) => Plugin[] + getSortedPluginHooks: ( + hookName: K + ) => NonNullable>[] +} + export type ResolveFn = ( id: string, importer?: string, @@ -431,9 +442,11 @@ export async function resolveConfig( // run config hooks const userPlugins = [...prePlugins, ...normalPlugins, ...postPlugins] - for (const p of userPlugins) { - if (p.config) { - const res = await p.config(config, configEnv) + for (const p of getSortedPluginsByHook('config', userPlugins)) { + const hook = p.config + const handler = hook && 'handler' in hook ? hook.handler : hook + if (handler) { + const res = await handler(config, configEnv) if (res) { config = mergeConfig(config, res) } @@ -598,9 +611,11 @@ export async function resolveConfig( ...workerNormalPlugins, ...workerPostPlugins ] - for (const p of workerUserPlugins) { - if (p.config) { - const res = await p.config(workerConfig, configEnv) + for (const p of getSortedPluginsByHook('config', workerUserPlugins)) { + const hook = p.config + const handler = hook && 'handler' in hook ? hook.handler : hook + if (handler) { + const res = await handler(workerConfig, configEnv) if (res) { workerConfig = mergeConfig(workerConfig, res) } @@ -609,7 +624,9 @@ export async function resolveConfig( const resolvedWorkerOptions: ResolveWorkerOptions = { format: workerConfig.worker?.format || 'iife', plugins: [], - rollupOptions: workerConfig.worker?.rollupOptions || {} + rollupOptions: workerConfig.worker?.rollupOptions || {}, + getSortedPlugins: undefined!, + getSortedPluginHooks: undefined! } const resolvedConfig: ResolvedConfig = { @@ -660,7 +677,9 @@ export async function resolveConfig( importGlobRestoreExtension: false, hmrPartialAccept: false, ...config.experimental - } + }, + getSortedPlugins: undefined!, + getSortedPluginHooks: undefined! } const resolved: ResolvedConfig = { ...config, @@ -673,6 +692,7 @@ export async function resolveConfig( normalPlugins, postPlugins ) + Object.assign(resolved, createPluginHookUtils(resolved.plugins)) const workerResolved: ResolvedConfig = { ...workerConfig, @@ -680,24 +700,26 @@ export async function resolveConfig( isWorker: true, mainConfig: resolved } - resolvedConfig.worker.plugins = await resolvePlugins( workerResolved, workerPrePlugins, workerNormalPlugins, workerPostPlugins ) + Object.assign( + resolvedConfig.worker, + createPluginHookUtils(resolvedConfig.worker.plugins) + ) // call configResolved hooks - await Promise.all( - userPlugins - .map((p) => p.configResolved?.(resolved)) - .concat( - resolvedConfig.worker.plugins.map((p) => - p.configResolved?.(workerResolved) - ) - ) - ) + await Promise.all([ + ...resolved + .getSortedPluginHooks('configResolved') + .map((hook) => hook(resolved)), + ...resolvedConfig.worker + .getSortedPluginHooks('configResolved') + .map((hook) => hook(workerResolved)) + ]) // validate config diff --git a/packages/vite/src/node/index.ts b/packages/vite/src/node/index.ts index 7dfada6825780b..c595ff0aa7e7e3 100644 --- a/packages/vite/src/node/index.ts +++ b/packages/vite/src/node/index.ts @@ -50,7 +50,7 @@ export type { SSRFormat, SSRTarget } from './ssr' -export type { Plugin } from './plugin' +export type { Plugin, HookHandler } from './plugin' export type { PackageCache, PackageData } from './packages' export type { Logger, diff --git a/packages/vite/src/node/plugin.ts b/packages/vite/src/node/plugin.ts index 69b19415b0daa7..a30006ec7915f5 100644 --- a/packages/vite/src/node/plugin.ts +++ b/packages/vite/src/node/plugin.ts @@ -1,6 +1,7 @@ import type { CustomPluginOptions, LoadResult, + ObjectHook, PluginContext, ResolveIdResult, Plugin as RollupPlugin, @@ -63,14 +64,16 @@ export interface Plugin extends RollupPlugin { * Note: User plugins are resolved before running this hook so injecting other * plugins inside the `config` hook will have no effect. */ - config?: ( - config: UserConfig, - env: ConfigEnv - ) => UserConfig | null | void | Promise + config?: ObjectHook< + ( + config: UserConfig, + env: ConfigEnv + ) => UserConfig | null | void | Promise + > /** * Use this hook to read and store the final resolved vite config. */ - configResolved?: (config: ResolvedConfig) => void | Promise + configResolved?: ObjectHook<(config: ResolvedConfig) => void | Promise> /** * Configure the vite server. The hook receives the {@link ViteDevServer} * instance. This can also be used to store a reference to the server @@ -80,7 +83,7 @@ export interface Plugin extends RollupPlugin { * can return a post hook that will be called after internal middlewares * are applied. Hook can be async functions and will be called in series. */ - configureServer?: ServerHook + configureServer?: ObjectHook /** * Configure the preview server. The hook receives the connect server and * its underlying http server. @@ -89,7 +92,7 @@ export interface Plugin extends RollupPlugin { * return a post hook that will be called after other middlewares are * applied. Hooks can be async functions and will be called in series. */ - configurePreviewServer?: PreviewServerHook + configurePreviewServer?: ObjectHook /** * Transform index.html. * The hook receives the following arguments: @@ -121,36 +124,46 @@ export interface Plugin extends RollupPlugin { * - If the hook doesn't return a value, the hmr update will be performed as * normal. */ - handleHotUpdate?( - ctx: HmrContext - ): Array | void | Promise | void> + handleHotUpdate?: ObjectHook< + ( + ctx: HmrContext + ) => Array | void | Promise | void> + > /** * extend hooks with ssr flag */ - resolveId?: ( - this: PluginContext, - source: string, - importer: string | undefined, - options: { - custom?: CustomPluginOptions - ssr?: boolean - /** - * @internal - */ - scan?: boolean - isEntry: boolean - } - ) => Promise | ResolveIdResult - load?: ( - this: PluginContext, - id: string, - options?: { ssr?: boolean } - ) => Promise | LoadResult - transform?: ( - this: TransformPluginContext, - code: string, - id: string, - options?: { ssr?: boolean } - ) => Promise | TransformResult + resolveId?: ObjectHook< + ( + this: PluginContext, + source: string, + importer: string | undefined, + options: { + custom?: CustomPluginOptions + ssr?: boolean + /** + * @internal + */ + scan?: boolean + isEntry: boolean + } + ) => Promise | ResolveIdResult + > + load?: ObjectHook< + ( + this: PluginContext, + id: string, + options?: { ssr?: boolean } + ) => Promise | LoadResult + > + transform?: ObjectHook< + ( + this: TransformPluginContext, + code: string, + id: string, + options?: { ssr?: boolean } + ) => Promise | TransformResult + > } + +export type HookHandler = T extends ObjectHook ? H : T diff --git a/packages/vite/src/node/plugins/index.ts b/packages/vite/src/node/plugins/index.ts index a2fbebcc75b66e..75c8297bf26919 100644 --- a/packages/vite/src/node/plugins/index.ts +++ b/packages/vite/src/node/plugins/index.ts @@ -1,7 +1,7 @@ import aliasPlugin from '@rollup/plugin-alias' -import type { ResolvedConfig } from '../config' +import type { PluginHookUtils, ResolvedConfig } from '../config' import { isDepsOptimizerEnabled } from '../config' -import type { Plugin } from '../plugin' +import type { HookHandler, Plugin } from '../plugin' import { getDepsOptimizer } from '../optimizer' import { shouldExternalizeForSSR } from '../ssr/ssrExternal' import { jsonPlugin } from './json' @@ -99,3 +99,60 @@ export async function resolvePlugins( : [clientInjectionsPlugin(config), importAnalysisPlugin(config)]) ].filter(Boolean) as Plugin[] } + +export function createPluginHookUtils( + plugins: readonly Plugin[] +): PluginHookUtils { + // sort plugins per hook + const sortedPluginsCache = new Map() + function getSortedPlugins(hookName: keyof Plugin): Plugin[] { + if (sortedPluginsCache.has(hookName)) + return sortedPluginsCache.get(hookName)! + const sorted = getSortedPluginsByHook(hookName, plugins) + sortedPluginsCache.set(hookName, sorted) + return sorted + } + function getSortedPluginHooks( + hookName: K + ): NonNullable>[] { + const plugins = getSortedPlugins(hookName) + return plugins + .map((p) => { + const hook = p[hookName]! + // @ts-expect-error cast + return 'handler' in hook ? hook.handler : hook + }) + .filter(Boolean) + } + + return { + getSortedPlugins, + getSortedPluginHooks + } +} + +export function getSortedPluginsByHook( + hookName: keyof Plugin, + plugins: readonly Plugin[] +): Plugin[] { + const pre: Plugin[] = [] + const normal: Plugin[] = [] + const post: Plugin[] = [] + for (const plugin of plugins) { + const hook = plugin[hookName] + if (hook) { + if (typeof hook === 'object') { + if (hook.order === 'pre') { + pre.push(plugin) + continue + } + if (hook.order === 'post') { + post.push(plugin) + continue + } + } + normal.push(plugin) + } + } + return [...pre, ...normal, ...post] +} diff --git a/packages/vite/src/node/plugins/worker.ts b/packages/vite/src/node/plugins/worker.ts index 25aa49d38a966a..336562d4326dd2 100644 --- a/packages/vite/src/node/plugins/worker.ts +++ b/packages/vite/src/node/plugins/worker.ts @@ -237,7 +237,6 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin { injectEnv = module?.transformResult?.code || '' } } - return { code: injectEnv + raw } diff --git a/packages/vite/src/node/preview.ts b/packages/vite/src/node/preview.ts index 2a563575c69ce1..71533111678e27 100644 --- a/packages/vite/src/node/preview.ts +++ b/packages/vite/src/node/preview.ts @@ -87,12 +87,8 @@ export async function preview( // apply server hooks from plugins const postHooks: ((() => void) | void)[] = [] - for (const plugin of config.plugins) { - if (plugin.configurePreviewServer) { - postHooks.push( - await plugin.configurePreviewServer({ middlewares: app, httpServer }) - ) - } + for (const hook of config.getSortedPluginHooks('configurePreviewServer')) { + postHooks.push(await hook({ middlewares: app, httpServer })) } // cors diff --git a/packages/vite/src/node/server/hmr.ts b/packages/vite/src/node/server/hmr.ts index a4de1284a7e050..f3298944a5e0b0 100644 --- a/packages/vite/src/node/server/hmr.ts +++ b/packages/vite/src/node/server/hmr.ts @@ -93,12 +93,10 @@ export async function handleHMRUpdate( server } - for (const plugin of config.plugins) { - if (plugin.handleHotUpdate) { - const filteredModules = await plugin.handleHotUpdate(hmrContext) - if (filteredModules) { - hmrContext.modules = filteredModules - } + for (const hook of config.getSortedPluginHooks('handleHotUpdate')) { + const filteredModules = await hook(hmrContext) + if (filteredModules) { + hmrContext.modules = filteredModules } } diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index 1fe2aadc926317..a105e15d574812 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -493,10 +493,8 @@ export async function createServer( // apply server configuration hooks from plugins const postHooks: ((() => void) | void)[] = [] - for (const plugin of config.plugins) { - if (plugin.configureServer) { - postHooks.push(await plugin.configureServer(server)) - } + for (const hook of config.getSortedPluginHooks('configureServer')) { + postHooks.push(await hook(server)) } // Internal middlewares ------------------------------------------------------ diff --git a/packages/vite/src/node/server/pluginContainer.ts b/packages/vite/src/node/server/pluginContainer.ts index fc1523fc7888a0..f44efd1fcd26b7 100644 --- a/packages/vite/src/node/server/pluginContainer.ts +++ b/packages/vite/src/node/server/pluginContainer.ts @@ -34,14 +34,17 @@ import { join, resolve } from 'node:path' import { performance } from 'node:perf_hooks' import { createRequire } from 'node:module' import type { + AsyncPluginHooks, CustomPluginOptions, EmittedFile, + FunctionPluginHooks, InputOptions, LoadResult, MinimalPluginContext, ModuleInfo, NormalizedInputOptions, OutputOptions, + ParallelPluginHooks, PartialResolvedId, ResolvedId, RollupError, @@ -74,6 +77,7 @@ import { } from '../utils' import { FS_PREFIX } from '../constants' import type { ResolvedConfig } from '../config' +import { createPluginHookUtils } from '../plugins' import { buildErrorMessage } from './middlewares/error' import type { ModuleGraph } from './moduleGraph' @@ -137,11 +141,19 @@ type PluginContext = Omit< export let parser = acorn.Parser export async function createPluginContainer( - { plugins, logger, root, build: { rollupOptions } }: ResolvedConfig, + config: ResolvedConfig, moduleGraph?: ModuleGraph, watcher?: FSWatcher ): Promise { const isDebug = process.env.DEBUG + const { + plugins, + logger, + root, + build: { rollupOptions } + } = config + const { getSortedPluginHooks, getSortedPlugins } = + createPluginHookUtils(plugins) const seenResolves: Record = {} const debugResolve = createDebugger('vite:resolve') @@ -192,6 +204,28 @@ export async function createPluginContainer( ) } + // parallel, ignores returns + async function hookParallel( + hookName: H, + context: (plugin: Plugin) => ThisType, + args: (plugin: Plugin) => Parameters + ): Promise { + const parallelPromises: Promise[] = [] + for (const plugin of getSortedPlugins(hookName)) { + const hook = plugin[hookName] + if (!hook) continue + const handler: Function = 'handler' in hook ? hook.handler : hook + if ((hook as { sequential?: boolean }).sequential) { + await Promise.all(parallelPromises) + parallelPromises.length = 0 + await handler.apply(context(plugin), args(plugin)) + } else { + parallelPromises.push(handler.apply(context(plugin), args(plugin))) + } + } + await Promise.all(parallelPromises) + } + // throw when an unsupported ModuleInfo property is accessed, // so that incompatible plugins fail in a non-cryptic way. const ModuleInfoProxy: ProxyHandler = { @@ -500,10 +534,8 @@ export async function createPluginContainer( const container: PluginContainer = { options: await (async () => { let options = rollupOptions - for (const plugin of plugins) { - if (!plugin.options) continue - options = - (await plugin.options.call(minimalContext, options)) || options + for (const optionsHook of getSortedPluginHooks('options')) { + options = (await optionsHook.call(minimalContext, options)) || options } if (options.acornInjectPlugins) { parser = acorn.Parser.extend( @@ -520,15 +552,10 @@ export async function createPluginContainer( getModuleInfo, async buildStart() { - await Promise.all( - plugins.map((plugin) => { - if (plugin.buildStart) { - return plugin.buildStart.call( - new Context(plugin) as any, - container.options as NormalizedInputOptions - ) - } - }) + await hookParallel( + 'buildStart', + (plugin) => new Context(plugin), + () => [container.options as NormalizedInputOptions] ) }, @@ -544,24 +571,23 @@ export async function createPluginContainer( let id: string | null = null const partial: Partial = {} - for (const plugin of plugins) { + for (const plugin of getSortedPlugins('resolveId')) { if (!plugin.resolveId) continue if (skip?.has(plugin)) continue ctx._activePlugin = plugin const pluginResolveStart = isDebug ? performance.now() : 0 - const result = await plugin.resolveId.call( - ctx as any, - rawId, - importer, - { - custom: options?.custom, - isEntry: !!options?.isEntry, - ssr, - scan - } - ) + const handler = + 'handler' in plugin.resolveId + ? plugin.resolveId.handler + : plugin.resolveId + const result = await handler.call(ctx as any, rawId, importer, { + custom: options?.custom, + isEntry: !!options?.isEntry, + ssr, + scan + }) if (!result) continue if (typeof result === 'string') { @@ -607,10 +633,12 @@ export async function createPluginContainer( const ssr = options?.ssr const ctx = new Context() ctx.ssr = !!ssr - for (const plugin of plugins) { + for (const plugin of getSortedPlugins('load')) { if (!plugin.load) continue ctx._activePlugin = plugin - const result = await plugin.load.call(ctx as any, id, { ssr }) + const handler = + 'handler' in plugin.load ? plugin.load.handler : plugin.load + const result = await handler.call(ctx as any, id, { ssr }) if (result != null) { if (isObject(result)) { updateModuleInfo(id, result) @@ -626,15 +654,19 @@ export async function createPluginContainer( const ssr = options?.ssr const ctx = new TransformContext(id, code, inMap as SourceMap) ctx.ssr = !!ssr - for (const plugin of plugins) { + for (const plugin of getSortedPlugins('transform')) { if (!plugin.transform) continue ctx._activePlugin = plugin ctx._activeId = id ctx._activeCode = code const start = isDebug ? performance.now() : 0 let result: TransformResult | string | undefined + const handler = + 'handler' in plugin.transform + ? plugin.transform.handler + : plugin.transform try { - result = await plugin.transform.call(ctx as any, code, id, { ssr }) + result = await handler.call(ctx as any, code, id, { ssr }) } catch (e) { ctx.error(e) } @@ -670,11 +702,15 @@ export async function createPluginContainer( async close() { if (closed) return const ctx = new Context() - await Promise.all( - plugins.map((p) => p.buildEnd && p.buildEnd.call(ctx as any)) + await hookParallel( + 'buildEnd', + () => ctx, + () => [] ) - await Promise.all( - plugins.map((p) => p.closeBundle && p.closeBundle.call(ctx as any)) + await hookParallel( + 'closeBundle', + () => ctx, + () => [] ) closed = true } diff --git a/playground/lib/__tests__/lib.spec.ts b/playground/lib/__tests__/lib.spec.ts index 54a7613d04cdce..0f9b837aab2b3f 100644 --- a/playground/lib/__tests__/lib.spec.ts +++ b/playground/lib/__tests__/lib.spec.ts @@ -24,7 +24,7 @@ describe.runIf(isBuild)('build', () => { expect(await page.textContent('.iife')).toBe('It works') const code = readFile('dist/my-lib-custom-filename.iife.js') // esbuild helpers are injected inside of the IIFE wrapper - expect(code).toMatch(/^const MyLib=function\(\){"use strict";/) + expect(code).toMatch(/^var MyLib=function\(\){"use strict";/) }) test('Library mode does not include `preload`', async () => { diff --git a/playground/object-hooks/__tests__/object-hooks.spec.ts b/playground/object-hooks/__tests__/object-hooks.spec.ts new file mode 100644 index 00000000000000..8e6de2d23025f6 --- /dev/null +++ b/playground/object-hooks/__tests__/object-hooks.spec.ts @@ -0,0 +1,6 @@ +import { expect, test } from 'vitest' +import { page } from '~utils' + +test('object hooks', async () => { + expect(await page.textContent('#transform')).toMatch('ok') +}) diff --git a/playground/object-hooks/index.html b/playground/object-hooks/index.html new file mode 100644 index 00000000000000..008ef32c159a6d --- /dev/null +++ b/playground/object-hooks/index.html @@ -0,0 +1,4 @@ +

Transform Hook order

+
+ + diff --git a/playground/object-hooks/main.ts b/playground/object-hooks/main.ts new file mode 100644 index 00000000000000..8e4878d209bf9e --- /dev/null +++ b/playground/object-hooks/main.ts @@ -0,0 +1,2 @@ +const app = document.getElementById('transform') +app.innerText = '__TRANSFORM__' diff --git a/playground/object-hooks/package.json b/playground/object-hooks/package.json new file mode 100644 index 00000000000000..380aaa142fd0c4 --- /dev/null +++ b/playground/object-hooks/package.json @@ -0,0 +1,14 @@ +{ + "name": "test-extensions", + "private": true, + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "vite build", + "debug": "node --inspect-brk ../../packages/vite/bin/vite", + "preview": "vite preview" + }, + "dependencies": { + "vue": "^3.2.37" + } +} diff --git a/playground/object-hooks/vite.config.ts b/playground/object-hooks/vite.config.ts new file mode 100644 index 00000000000000..554462dc730df3 --- /dev/null +++ b/playground/object-hooks/vite.config.ts @@ -0,0 +1,69 @@ +/* eslint-disable import/no-nodejs-modules */ +import assert from 'assert' +import { defineConfig } from 'vite' + +let count = 0 +export default defineConfig({ + plugins: [ + { + name: 'plugin1', + buildStart: { + async handler() { + await new Promise((r) => setTimeout(r, 100)) + count += 1 + } + }, + transform: { + order: 'post', + handler(code) { + return code.replace('__TRANSFORM3__', 'ok') + } + } + }, + { + name: 'plugin2', + buildStart: { + sequential: true, + async handler() { + assert(count === 1) + await new Promise((r) => setTimeout(r, 100)) + count += 1 + } + }, + transform: { + handler(code) { + return code.replace('__TRANSFORM1__', '__TRANSFORM2__') + } + } + }, + { + name: 'plugin3', + buildStart: { + async handler() { + assert(count === 2) + await new Promise((r) => setTimeout(r, 100)) + count += 1 + } + }, + transform: { + order: 'pre', + handler(code) { + return code.replace('__TRANSFORM__', '__TRANSFORM1__') + } + } + }, + { + name: 'plugin4', + buildStart: { + async handler() { + assert(count === 2) + } + }, + transform: { + handler(code) { + return code.replace('__TRANSFORM2__', '__TRANSFORM3__') + } + } + } + ] +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8a0a8309eddca4..a424c935ca9be2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,7 +51,7 @@ importers: prettier: 2.7.1 prompts: ^2.4.2 rimraf: ^3.0.2 - rollup: '>=2.75.6 <2.77.0 || ~2.77.0' + rollup: ~2.78.0 semver: ^7.3.7 simple-git-hooks: ^2.8.0 tslib: ^2.4.0 @@ -65,7 +65,7 @@ importers: devDependencies: '@babel/types': 7.18.10 '@microsoft/api-extractor': 7.29.2 - '@rollup/plugin-typescript': 8.3.4_nzsoit4cp576bo3qoi6msb73em + '@rollup/plugin-typescript': 8.3.4_7emp2e44zzc74lnyjhc37gdv4y '@types/babel__core': 7.1.19 '@types/babel__standalone': 7.1.4 '@types/convert-source-map': 1.5.2 @@ -104,7 +104,7 @@ importers: prettier: 2.7.1 prompts: 2.4.2 rimraf: 3.0.2 - rollup: 2.77.0 + rollup: 2.78.0 semver: 7.3.7 simple-git-hooks: 2.8.0 tslib: 2.4.0 @@ -171,7 +171,7 @@ importers: '@jridgewell/gen-mapping': ^0.3.2 '@jridgewell/trace-mapping': ^0.3.15 debug: ^4.3.4 - rollup: '>=2.75.6 <2.77.0 || ~2.77.0' + rollup: ~2.78.0 slash: ^4.0.0 source-map: ^0.6.1 vite: workspace:* @@ -180,7 +180,7 @@ importers: '@jridgewell/gen-mapping': 0.3.2 '@jridgewell/trace-mapping': 0.3.15 debug: 4.3.4 - rollup: 2.77.0 + rollup: 2.78.0 slash: 4.0.0 source-map: 0.6.1 vite: link:../vite @@ -249,7 +249,7 @@ importers: postcss-modules: ^5.0.0 resolve: ^1.22.1 resolve.exports: ^1.1.0 - rollup: '>=2.75.6 <2.77.0 || ~2.77.0' + rollup: ~2.78.0 rollup-plugin-license: ^2.8.1 sirv: ^2.0.2 source-map-js: ^1.0.2 @@ -265,7 +265,7 @@ importers: esbuild: 0.14.47 postcss: 8.4.16 resolve: 1.22.1 - rollup: 2.77.0 + rollup: 2.78.0 optionalDependencies: fsevents: 2.3.2 devDependencies: @@ -273,12 +273,12 @@ importers: '@babel/parser': 7.18.11 '@babel/types': 7.18.10 '@jridgewell/trace-mapping': 0.3.15 - '@rollup/plugin-alias': 3.1.9_rollup@2.77.0 - '@rollup/plugin-commonjs': 22.0.2_rollup@2.77.0 - '@rollup/plugin-dynamic-import-vars': 1.4.4_rollup@2.77.0 - '@rollup/plugin-json': 4.1.0_rollup@2.77.0 - '@rollup/plugin-node-resolve': 13.3.0_rollup@2.77.0 - '@rollup/plugin-typescript': 8.3.4_rollup@2.77.0+tslib@2.4.0 + '@rollup/plugin-alias': 3.1.9_rollup@2.78.0 + '@rollup/plugin-commonjs': 22.0.2_rollup@2.78.0 + '@rollup/plugin-dynamic-import-vars': 1.4.4_rollup@2.78.0 + '@rollup/plugin-json': 4.1.0_rollup@2.78.0 + '@rollup/plugin-node-resolve': 13.3.0_rollup@2.78.0 + '@rollup/plugin-typescript': 8.3.4_rollup@2.78.0+tslib@2.4.0 '@rollup/pluginutils': 4.2.1 '@vue/compiler-dom': 3.2.37 acorn: 8.8.0 @@ -311,7 +311,7 @@ importers: postcss-load-config: 4.0.1_postcss@8.4.16 postcss-modules: 5.0.0_postcss@8.4.16 resolve.exports: 1.1.0 - rollup-plugin-license: 2.8.1_rollup@2.77.0 + rollup-plugin-license: 2.8.1_rollup@2.78.0 sirv: 2.0.2 source-map-js: 1.0.2 source-map-support: 0.5.21 @@ -613,6 +613,12 @@ importers: dependencies: test-package-e-excluded: link:../test-package-e-excluded + playground/object-hooks: + specifiers: + vue: ^3.2.37 + dependencies: + vue: 3.2.37 + playground/optimize-deps: specifiers: '@vitejs/plugin-vue': workspace:* @@ -2372,16 +2378,6 @@ packages: resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} dev: true - /@rollup/plugin-alias/3.1.9_rollup@2.77.0: - resolution: {integrity: sha512-QI5fsEvm9bDzt32k39wpOwZhVzRcL5ydcffUHMyLVaVaLeC70I8TJZ17F1z1eMoLu4E/UOcH9BWVkKpIKdrfiw==} - engines: {node: '>=8.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0 - dependencies: - rollup: 2.77.0 - slash: 3.0.0 - dev: true - /@rollup/plugin-alias/3.1.9_rollup@2.78.0: resolution: {integrity: sha512-QI5fsEvm9bDzt32k39wpOwZhVzRcL5ydcffUHMyLVaVaLeC70I8TJZ17F1z1eMoLu4E/UOcH9BWVkKpIKdrfiw==} engines: {node: '>=8.0.0'} @@ -2392,22 +2388,6 @@ packages: slash: 3.0.0 dev: true - /@rollup/plugin-commonjs/22.0.2_rollup@2.77.0: - resolution: {integrity: sha512-//NdP6iIwPbMTcazYsiBMbJW7gfmpHom33u1beiIoHDEM0Q9clvtQB1T0efvMqHeKsGohiHo97BCPCkBXdscwg==} - engines: {node: '>= 12.0.0'} - peerDependencies: - rollup: ^2.68.0 - dependencies: - '@rollup/pluginutils': 3.1.0_rollup@2.77.0 - commondir: 1.0.1 - estree-walker: 2.0.2 - glob: 7.2.0 - is-reference: 1.2.1 - magic-string: 0.25.9 - resolve: 1.22.1 - rollup: 2.77.0 - dev: true - /@rollup/plugin-commonjs/22.0.2_rollup@2.78.0: resolution: {integrity: sha512-//NdP6iIwPbMTcazYsiBMbJW7gfmpHom33u1beiIoHDEM0Q9clvtQB1T0efvMqHeKsGohiHo97BCPCkBXdscwg==} engines: {node: '>= 12.0.0'} @@ -2424,7 +2404,7 @@ packages: rollup: 2.78.0 dev: true - /@rollup/plugin-dynamic-import-vars/1.4.4_rollup@2.77.0: + /@rollup/plugin-dynamic-import-vars/1.4.4_rollup@2.78.0: resolution: {integrity: sha512-51BcU6ag9EeF09CtEsa5D/IHYo7KI42TR1Jc4doNzV1nHAiH7TvUi5vsLERFMjs9Gzy9K0otbZH/2wb0hpBhRA==} engines: {node: '>= 10.0.0'} peerDependencies: @@ -2434,16 +2414,7 @@ packages: estree-walker: 2.0.2 fast-glob: 3.2.11 magic-string: 0.25.9 - rollup: 2.77.0 - dev: true - - /@rollup/plugin-json/4.1.0_rollup@2.77.0: - resolution: {integrity: sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==} - peerDependencies: - rollup: ^1.20.0 || ^2.0.0 - dependencies: - '@rollup/pluginutils': 3.1.0_rollup@2.77.0 - rollup: 2.77.0 + rollup: 2.78.0 dev: true /@rollup/plugin-json/4.1.0_rollup@2.78.0: @@ -2455,21 +2426,6 @@ packages: rollup: 2.78.0 dev: true - /@rollup/plugin-node-resolve/13.3.0_rollup@2.77.0: - resolution: {integrity: sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==} - engines: {node: '>= 10.0.0'} - peerDependencies: - rollup: ^2.42.0 - dependencies: - '@rollup/pluginutils': 3.1.0_rollup@2.77.0 - '@types/resolve': 1.17.1 - deepmerge: 4.2.2 - is-builtin-module: 3.1.0 - is-module: 1.0.0 - resolve: 1.22.1 - rollup: 2.77.0 - dev: true - /@rollup/plugin-node-resolve/13.3.0_rollup@2.78.0: resolution: {integrity: sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==} engines: {node: '>= 10.0.0'} @@ -2495,7 +2451,7 @@ packages: rollup: 2.78.0 dev: true - /@rollup/plugin-typescript/8.3.4_nzsoit4cp576bo3qoi6msb73em: + /@rollup/plugin-typescript/8.3.4_7emp2e44zzc74lnyjhc37gdv4y: resolution: {integrity: sha512-wt7JnYE9antX6BOXtsxGoeVSu4dZfw0dU3xykfOQ4hC3EddxRbVG/K0xiY1Wup7QOHJcjLYXWAn0Kx9Z1SBHHg==} engines: {node: '>=8.0.0'} peerDependencies: @@ -2506,14 +2462,14 @@ packages: tslib: optional: true dependencies: - '@rollup/pluginutils': 3.1.0_rollup@2.77.0 + '@rollup/pluginutils': 3.1.0_rollup@2.78.0 resolve: 1.22.1 - rollup: 2.77.0 + rollup: 2.78.0 tslib: 2.4.0 typescript: 4.6.4 dev: true - /@rollup/plugin-typescript/8.3.4_rollup@2.77.0+tslib@2.4.0: + /@rollup/plugin-typescript/8.3.4_rollup@2.78.0+tslib@2.4.0: resolution: {integrity: sha512-wt7JnYE9antX6BOXtsxGoeVSu4dZfw0dU3xykfOQ4hC3EddxRbVG/K0xiY1Wup7QOHJcjLYXWAn0Kx9Z1SBHHg==} engines: {node: '>=8.0.0'} peerDependencies: @@ -2524,24 +2480,12 @@ packages: tslib: optional: true dependencies: - '@rollup/pluginutils': 3.1.0_rollup@2.77.0 + '@rollup/pluginutils': 3.1.0_rollup@2.78.0 resolve: 1.22.1 - rollup: 2.77.0 + rollup: 2.78.0 tslib: 2.4.0 dev: true - /@rollup/pluginutils/3.1.0_rollup@2.77.0: - resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} - engines: {node: '>= 8.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0 - dependencies: - '@types/estree': 0.0.39 - estree-walker: 1.0.1 - picomatch: 2.3.1 - rollup: 2.77.0 - dev: true - /@rollup/pluginutils/3.1.0_rollup@2.78.0: resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} engines: {node: '>= 8.0.0'} @@ -7923,7 +7867,7 @@ packages: - supports-color dev: true - /rollup-plugin-license/2.8.1_rollup@2.77.0: + /rollup-plugin-license/2.8.1_rollup@2.78.0: resolution: {integrity: sha512-VYd9pzaNL7NN6xQp93XiiCV2UoduXgSmTcz6rl9bHPdiifT6yH3Zw/omEr73Rq8TIyN4nqJACBbKIT/2eE66wg==} engines: {node: '>=10.0.0'} peerDependencies: @@ -7936,25 +7880,17 @@ packages: mkdirp: 1.0.4 moment: 2.29.3 package-name-regex: 2.0.6 - rollup: 2.77.0 + rollup: 2.78.0 spdx-expression-validate: 2.0.0 spdx-satisfies: 5.0.1 dev: true - /rollup/2.77.0: - resolution: {integrity: sha512-vL8xjY4yOQEw79DvyXLijhnhh+R/O9zpF/LEgkCebZFtb6ELeN9H3/2T0r8+mp+fFTBHZ5qGpOpW2ela2zRt3g==} - engines: {node: '>=10.0.0'} - hasBin: true - optionalDependencies: - fsevents: 2.3.2 - /rollup/2.78.0: resolution: {integrity: sha512-4+YfbQC9QEVvKTanHhIAFVUFSRsezvQF8vFOJwtGfb9Bb+r014S+qryr9PSmw8x6sMnPkmFBGAvIFVQxvJxjtg==} engines: {node: '>=10.0.0'} hasBin: true optionalDependencies: fsevents: 2.3.2 - dev: true /run-parallel/1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}