From 027d10c24d994ebccb032240a70a267220a1f1ec Mon Sep 17 00:00:00 2001 From: Mathieu Audebert Date: Fri, 9 Oct 2026 13:10:25 +0200 Subject: [PATCH] fix(rsc): keep CSS wrappers out of a trailing comment when a module has no final newline --- .../src/transforms/wrap-export.test.ts | 20 +++++++++++++++++++ .../plugin-rsc/src/transforms/wrap-export.ts | 7 ++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/plugin-rsc/src/transforms/wrap-export.test.ts b/packages/plugin-rsc/src/transforms/wrap-export.test.ts index 0d745600c..b556eb56b 100644 --- a/packages/plugin-rsc/src/transforms/wrap-export.test.ts +++ b/packages/plugin-rsc/src/transforms/wrap-export.test.ts @@ -70,6 +70,26 @@ export class Cls {}; `) }) + test('module without a final newline', async () => { + // Published packages often end with a source map comment and no newline. + const input = `export const Arrow = () => {};\nexport function Fn() {};\n//# sourceMappingURL=index.js.map` + const output = await testTransform(input) + expect(output).toMatchInlineSnapshot(` + "let Arrow = () => {}; + function Fn() {}; + //# sourceMappingURL=index.js.map + Arrow = /* #__PURE__ */ $$wrap(Arrow, "", "Arrow"); + export { Arrow }; + Fn = /* #__PURE__ */ $$wrap(Fn, "", "Fn"); + export { Fn }; + " + `) + const lastLine = (output as string) + .split('\n') + .findLast((line) => line.includes('sourceMappingURL')) + expect(lastLine).toBe('//# sourceMappingURL=index.js.map') + }) + test('preserve reference', async () => { const input = ` export let count = 0; diff --git a/packages/plugin-rsc/src/transforms/wrap-export.ts b/packages/plugin-rsc/src/transforms/wrap-export.ts index c9b884f91..b9b6c42dc 100644 --- a/packages/plugin-rsc/src/transforms/wrap-export.ts +++ b/packages/plugin-rsc/src/transforms/wrap-export.ts @@ -71,6 +71,10 @@ export function transformWrapExport( const exportNames: string[] = [] const appendedCode: string[] = [] const filter = options.filter ?? (() => true) + // Code moved to the end of a module that has no final newline would join its + // last line. If that line is a comment (often `//# sourceMappingURL=...`), + // the moved code becomes part of the comment and never runs. + let needsLeadingNewline = !input.endsWith('\n') /** * Strips a direct export declaration and emits assignments and exports at @@ -113,8 +117,9 @@ export function transformWrapExport( .filter(Boolean) .join('') + `export { ${exports.map((e) => e.localName).join(', ')} };\n` - output.update(start, end, newCode) + output.update(start, end, (needsLeadingNewline ? '\n' : '') + newCode) output.move(start, end, input.length) + needsLeadingNewline = false } /**