Skip to content

Commit d94d400

Browse files
authored
Merge pull request #139 from marcalexiei/feature/insert-style-dedupe
issue-132 - dedupe insertStyle in output files
2 parents d832124 + 6d9d3e3 commit d94d400

File tree

12 files changed

+141
-38
lines changed

12 files changed

+141
-38
lines changed

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
},
1414
"scripts": {
1515
"prepare": "npm run build && npm test",
16-
"build": "npm run build-downlevel-dts && tsc --project tsconfig.json",
16+
"build": "npm run build-downlevel-dts && tsc --project tsconfig.build.plugin.json && tsc --project tsconfig.build.insertStyle.json",
1717
"build-downlevel-dts": "node scripts/clean-and-run-downlevel-dts.js",
1818
"downlevel-dts": "downlevel-dts . ts3.5 [--to=3.5]",
1919
"test": "nyc --reporter=html --reporter=text ava ./test/*.test.ts -s && npm run test:rollup.config.spec.ts",
@@ -54,7 +54,8 @@
5454
],
5555
"require": [
5656
"ts-node/register"
57-
]
57+
],
58+
"snapshotDir": "./test/snapshots"
5859
},
5960
"dependencies": {
6061
"@rollup/pluginutils": "^3 || ^4 || ^5",

src/index.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import * as sass from 'sass';
44
import {dirname} from 'path';
55
import * as fs from 'fs';
66
import {createFilter} from '@rollup/pluginutils';
7-
import {insertStyle} from './style';
87
import {
98
SassImporterResult,
109
RollupAssetInfo,
@@ -107,14 +106,20 @@ const MATCH_SASS_FILENAME_RE = /\.sass$/,
107106
const out = JSON.stringify(resolvedCss);
108107

109108
let defaultExport = `""`;
109+
let imports = '';
110110

111111
if (rollupOptions.insert) {
112+
/**
113+
* @see insertStyle.ts for additional information
114+
* Let rollup handle import by processing insertStyle as a module
115+
*/
116+
imports = `import ${insertFnName} from '${__dirname}/insertStyle.js';\n`;
112117
defaultExport = `${insertFnName}(${out});`;
113118
} else if (!rollupOptions.output) {
114119
defaultExport = out;
115120
}
116121

117-
return `export default ${defaultExport};\n${restExports}`;
122+
return `${imports}export default ${defaultExport};\n${restExports}`;
118123
}); // @note do not `catch` here - let error propagate to rollup level
119124
},
120125

@@ -152,12 +157,6 @@ export = function plugin(options = {} as RollupPluginSassOptions): RollupPlugin
152157
return {
153158
name: 'rollup-plugin-sass',
154159

155-
intro() {
156-
if (pluginOptions.insert) {
157-
return insertStyle.toString().replace(/insertStyle/, insertFnName);
158-
}
159-
},
160-
161160
transform(code: string, filePath: string): Promise<any> {
162161
if (!filter(filePath)) {
163162
return Promise.resolve();

src/insertStyle.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* Create a style tag and append to head tag
3+
*
4+
* @warning this file is not included directly in the source code!
5+
* If user specifies inject option to true, an import to this file will be injected in rollup output.
6+
* Due to this reason this file is compiled into a ESM module separated from other plugin source files.
7+
* That is the reason of why there are two tsconfig.build files.
8+
*
9+
* @return css style
10+
*/
11+
export default function insertStyle(css: string | undefined): string | undefined {
12+
if (!css || typeof window === 'undefined') {
13+
return;
14+
}
15+
16+
const style = document.createElement('style');
17+
style.setAttribute('type', 'text/css');
18+
style.innerHTML = css;
19+
20+
document.head.appendChild(style);
21+
22+
return css;
23+
}

src/style.ts

Lines changed: 0 additions & 21 deletions
This file was deleted.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import a from '../../assets/actual_a.scss';
2+
3+
export default a;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import b from '../../assets/actual_b.scss';
2+
3+
export default b;

test/index.test.ts

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1+
import test from 'ava';
12
import {promises as fs, constants as fsConstants} from 'fs';
23
import * as path from 'path';
3-
import test from 'ava';
44
import sinon from 'sinon';
55
import {OutputOptions, rollup, RollupOutput} from 'rollup';
66
import * as sassJs from 'sass';
7-
import sass from '../src/index';
8-
import {SassOptions} from "../src/types";
9-
import {error} from "../src/utils";
107
import postcss from "postcss";
118
import {extractICSS} from "icss-utils";
129

10+
import sass from "../src/index";
11+
import { SassOptions } from "../src/types";
12+
1313
const repoRoot = path.join(__dirname, '../'),
1414

1515
tmpDir = path.join(repoRoot, '.tests-output/'),
@@ -86,6 +86,22 @@ test('should import *.scss and *.sass files', async t => {
8686
t.true([expectA, expectB, expectC].every(xs => rslt.includes(xs)));
8787
});
8888

89+
test("should import *.scss and *.sass files with default configuration", async (t) => {
90+
const outputBundle = await rollup({
91+
input: "test/fixtures/basic/index.js",
92+
plugins: [
93+
sass(),
94+
],
95+
}),
96+
{ output } = await outputBundle.generate({
97+
format: "es",
98+
file: path.join(tmpDir, "import_scss_and_sass_default_options.js"),
99+
}),
100+
rslt = squash(unwrap(output));
101+
102+
t.snapshot(rslt)
103+
});
104+
89105
test('should compress the dest CSS', async t => {
90106
const outputBundle = await rollup({
91107
...baseConfig,
@@ -152,8 +168,51 @@ test('should insert CSS into head tag', async t => {
152168
}),
153169
{output} = await outputBundle.generate(generateOptions);
154170

155-
t.true(unwrap(output).includes('___$insertStyle("body{color:red}");'));
156-
t.true(unwrap(output).includes('___$insertStyle("body{color:green}");'));
171+
t.snapshot(unwrap(output));
172+
});
173+
174+
test("should generate chunks with import insertStyle when `insert` is true", async (t) => {
175+
const outputBundle = await rollup({
176+
input: {
177+
entryA: "test/fixtures/multiple-entry-points/entryA.js",
178+
entryB: "test/fixtures/multiple-entry-points/entryB.js",
179+
},
180+
plugins: [
181+
sass({
182+
insert: true,
183+
options: sassOptions,
184+
}),
185+
],
186+
output: {
187+
preserveModules: true,
188+
preserveModulesRoot: "src",
189+
},
190+
external: [/\/insertStyle\.js$/],
191+
});
192+
193+
const { output } = await outputBundle.generate(generateOptions);
194+
195+
t.is(output.length, 2, "has 2 chunks");
196+
t.true(
197+
output.every(
198+
(outputItem) => {
199+
if (outputItem.type === "chunk") {
200+
const insertStyleImportsCount = outputItem.imports.filter((it) =>
201+
it.includes("/insertStyle.js")
202+
).length;
203+
return insertStyleImportsCount === 1;
204+
}
205+
// if is an assets there is no need to check imports
206+
return true;
207+
}
208+
),
209+
"each chunk must include insertStyle once"
210+
);
211+
212+
// outputBundle.write({
213+
// format: 'es',
214+
// dir: path.join(tmpDir, 'insert-style-preserve-modules'),
215+
// });
157216
});
158217

159218
test('should support output as function', async t => {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Snapshot report for `test/index.test.ts`
2+
3+
The actual snapshot is saved in `index.test.ts.snap`.
4+
5+
Generated by [AVA](https://avajs.dev).
6+
7+
## should import *.scss and *.sass files with default configuration
8+
9+
> Snapshot 1
10+
11+
'var atualA = "body {\\n color: red;\\n}";var atualB = "body {\\n color: green;\\n}";var atualC = "body {\\n color: blue;\\n}";var index = atualA + atualB + atualC;export { index as default };'
12+
13+
## should insert CSS into head tag
14+
15+
> Snapshot 1
16+
17+
`import ___$insertStyle from '../../../src/insertStyle.js';␊
18+
19+
___$insertStyle("body{color:red}");␊
20+
21+
___$insertStyle("body{color:green}");␊
22+
`
348 Bytes
Binary file not shown.

test/style.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import test from 'ava';
22
import {readFileSync} from 'fs';
3-
import {insertStyle} from '../src/style';
3+
import insertStyle from '../src/insertStyle';
44
import jsdom from 'jsdom';
55

66
const expectA = readFileSync('test/assets/expect_a.css').toString();

0 commit comments

Comments
 (0)