From e5f124872a7257c41cb557021ac04935b4e9ca44 Mon Sep 17 00:00:00 2001 From: Ariel Weinberger Date: Fri, 6 Sep 2024 14:17:27 +0200 Subject: [PATCH 1/3] make injectStyle async --- src/esbuild/postcss.ts | 4 ++-- src/options.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/esbuild/postcss.ts b/src/esbuild/postcss.ts index 1c7540229..ec6fb599b 100644 --- a/src/esbuild/postcss.ts +++ b/src/esbuild/postcss.ts @@ -9,7 +9,7 @@ export const postcssPlugin = ({ cssLoader, }: { css?: Map - inject?: boolean | ((css: string, fileId: string) => string) + inject?: boolean | ((css: string, fileId: string) => Promise) cssLoader?: Loader }): Plugin => { return { @@ -124,7 +124,7 @@ export const postcssPlugin = ({ contents = typeof inject === 'function' - ? inject(JSON.stringify(contents), args.path) + ? await inject(JSON.stringify(contents), args.path) : `import styleInject from '#style-inject';styleInject(${JSON.stringify( contents, )})` diff --git a/src/options.ts b/src/options.ts index 68c8d3ff4..ed09cb5eb 100644 --- a/src/options.ts +++ b/src/options.ts @@ -210,7 +210,7 @@ export type Options = { * Inject CSS as style tags to document head * @default {false} */ - injectStyle?: boolean | ((css: string, fileId: string) => string) + injectStyle?: boolean | ((css: string, fileId: string) => Promise) /** * Inject cjs and esm shims if needed * @default false From 464bdf485c5f6235759314cab7c8d186a2816405 Mon Sep 17 00:00:00 2001 From: Ariel Weinberger Date: Fri, 6 Sep 2024 15:28:32 +0200 Subject: [PATCH 2/3] feat: support both sync and async injectStyle --- src/esbuild/postcss.ts | 13 ++++++------- src/options.ts | 2 +- test/index.test.ts | 26 +++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/esbuild/postcss.ts b/src/esbuild/postcss.ts index ec6fb599b..7312d7346 100644 --- a/src/esbuild/postcss.ts +++ b/src/esbuild/postcss.ts @@ -9,7 +9,7 @@ export const postcssPlugin = ({ cssLoader, }: { css?: Map - inject?: boolean | ((css: string, fileId: string) => Promise) + inject?: boolean | ((css: string, fileId: string) => string | Promise) cssLoader?: Loader }): Plugin => { return { @@ -122,12 +122,11 @@ export const postcssPlugin = ({ }) ).code - contents = - typeof inject === 'function' - ? await inject(JSON.stringify(contents), args.path) - : `import styleInject from '#style-inject';styleInject(${JSON.stringify( - contents, - )})` + contents = typeof inject === 'function' + ? await Promise.resolve(inject(JSON.stringify(contents), args.path)) + : `import styleInject from '#style-inject';styleInject(${JSON.stringify( + contents, + )})` return { contents, diff --git a/src/options.ts b/src/options.ts index ed09cb5eb..906ef994c 100644 --- a/src/options.ts +++ b/src/options.ts @@ -210,7 +210,7 @@ export type Options = { * Inject CSS as style tags to document head * @default {false} */ - injectStyle?: boolean | ((css: string, fileId: string) => Promise) + injectStyle?: boolean | ((css: string, fileId: string) => string | Promise) /** * Inject cjs and esm shims if needed * @default false diff --git a/test/index.test.ts b/test/index.test.ts index 5b07554fe..5b42572e2 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -806,7 +806,7 @@ test(`should generate export {} when there are no exports in source file`, async expect(await getFileContent('dist/input.d.mts')).toMatch(/export {\s*}/) }) -test('custom inject style function', async () => { +test('custom inject style function - sync', async () => { const { outFiles, getFileContent } = await run(getTestName(), { 'input.ts': `import './style.css'`, 'style.css': `.hello { color: red }`, @@ -829,6 +829,30 @@ test('custom inject style function', async () => { ) }) +test('custom inject style function - async', async () => { + const { outFiles, getFileContent } = await run(getTestName(), { + 'input.ts': `import './style.css'`, + 'style.css': `.hello { color: red }`, + 'tsup.config.ts': ` + export default { + entry: ['src/input.ts'], + minify: true, + format: ['esm', 'cjs'], + injectStyle: async (css) => { + await new Promise(resolve => setTimeout(resolve, 100)); + return "__custom_async_inject_style__(" + css +")"; + } + }`, + }) + expect(outFiles).toEqual(['input.js', 'input.mjs']) + expect(await getFileContent('dist/input.mjs')).toContain( + '__custom_async_inject_style__(`.hello{color:red}\n`)', + ) + expect(await getFileContent('dist/input.js')).toContain( + '__custom_async_inject_style__(`.hello{color:red}\n`)', + ) +}) + test('preserve top-level variable for IIFE format', async () => { const { outFiles, getFileContent } = await run(getTestName(), { 'input.ts': `export default 'foo'`, From 15c3512d0aef6842b80dd1e9be8079a352f64338 Mon Sep 17 00:00:00 2001 From: Ariel Weinberger Date: Fri, 6 Sep 2024 16:14:52 +0200 Subject: [PATCH 3/3] fix: DataCloneError when injectStyle is a function --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index d6987881a..a5150da12 100644 --- a/src/index.ts +++ b/src/index.ts @@ -232,6 +232,7 @@ export async function build(_options: Options) { configName: item?.name, options: { ...options, // functions cannot be cloned + injectStyle: typeof options.injectStyle === 'function' ? undefined : options.injectStyle, banner: undefined, footer: undefined, esbuildPlugins: undefined,