Skip to content

Commit c5780ad

Browse files
authored
rollup: Correctly strip side-effect imports (#1699)
1 parent 79b3519 commit c5780ad

5 files changed

Lines changed: 44 additions & 22 deletions

File tree

.changeset/many-parts-fail.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@vanilla-extract/rollup-plugin': patch
3+
---
4+
5+
Fixed a bug where side-effect `require`s would not be stripped when bundling CSS with the `extract` option

.changeset/twenty-rivers-smash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@vanilla-extract/rollup-plugin': patch
3+
---
4+
5+
Fixed a bug where side-effect imports would not be stripped in `.cjs` or `.mjs` files when bundling CSS with the `extract` option

packages/rollup-plugin/src/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,12 +211,13 @@ export function vanillaExtractPlugin({
211211
}
212212
await Promise.all(
213213
Object.entries(bundle).map(async ([id, chunk]) => {
214+
const isJsFile = /\.(m|c)?js$/.test(id);
214215
if (
215216
chunk.type === 'chunk' &&
216-
id.endsWith('.js') &&
217+
isJsFile &&
217218
chunk.imports.some((specifier) => extractedCssIds.has(specifier))
218219
) {
219-
chunk.code = await stripSideEffectImportsMatching(chunk.code, [
220+
chunk.code = stripSideEffectImportsMatching(chunk.code, [
220221
...extractedCssIds,
221222
]);
222223
}

packages/rollup-plugin/src/lib.ts

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -102,26 +102,17 @@ export function sortModules(modules: Record<string, ImportChain>): string[] {
102102
return sortedModules.map(([id]) => id);
103103
}
104104

105-
const SIDE_EFFECT_IMPORT_RE = /^\s*import\s+['"]([^'"]+)['"]\s*;?\s*/gm;
105+
const SIDE_EFFECT_IMPORT_RE =
106+
/^\s*(?:import\s+['"]([^'"]+)['"]|require\s*\(\s*['"]([^'"]+)['"]\s*\))\s*;?\s*/gm;
106107

107-
/** Remove specific side effect imports from JS */
108-
export function stripSideEffectImportsMatching(
108+
/** Remove specific side effect imports and requires from JS */
109+
export const stripSideEffectImportsMatching = (
109110
code: string,
110111
sources: string[],
111-
): string {
112-
const matches = code.matchAll(SIDE_EFFECT_IMPORT_RE);
113-
if (!matches) {
114-
return code;
115-
}
116-
let output = code;
117-
for (const match of matches) {
118-
if (!match[1] || !sources.includes(match[1])) {
119-
continue;
120-
}
121-
output = output.replace(match[0], '');
122-
}
123-
return output;
124-
}
112+
): string =>
113+
code.replace(SIDE_EFFECT_IMPORT_RE, (match, importSource, requireSource) =>
114+
sources.includes(importSource ?? requireSource) ? '' : match,
115+
);
125116

126117
export async function tryGetPackageName(cwd: string): Promise<string | null> {
127118
try {

packages/rollup-plugin/test/rollup-plugin.test.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,7 @@ describe('rollup-plugin', () => {
386386
});
387387

388388
describe('stripSideEffectImportsMatching', () => {
389-
it('strips only specified side effects', () => {
390-
// assert all specified imports are stripped
389+
it('strips only specified side effects in ESM', () => {
391390
expect(
392391
stripSideEffectImportsMatching(
393392
`import React from 'react';
@@ -410,7 +409,6 @@ export default function Button() {
410409
});
411410

412411
it('leaves code alone if no side effects specified', () => {
413-
// assert empty array returns code as expected
414412
const code = `import React from 'react';
415413
import 'button.vanilla.css';
416414
import './foobar.js';
@@ -420,4 +418,26 @@ export default function Button() {
420418
}`;
421419
expect(stripSideEffectImportsMatching(code, [])).toBe(code);
422420
});
421+
422+
it('strips only specified side effects in CJS', () => {
423+
expect(
424+
stripSideEffectImportsMatching(
425+
`const React = require('react');
426+
require('button.vanilla.css');
427+
require('./foobar.js');
428+
429+
module.exports = function Button() {
430+
return <button>My Button</button>;
431+
}`,
432+
['button.vanilla.css', 'checkbox.vanilla.css', 'radio.vanilla.css'],
433+
),
434+
).toBe(
435+
`const React = require('react');
436+
require('./foobar.js');
437+
438+
module.exports = function Button() {
439+
return <button>My Button</button>;
440+
}`,
441+
);
442+
});
423443
});

0 commit comments

Comments
 (0)