Skip to content

Commit

Permalink
feat: bundle specific ref-counting (#467)
Browse files Browse the repository at this point in the history
* per-bundle ref counting for css dependencies

Fixes  #466
  • Loading branch information
tivac committed Aug 10, 2018
1 parent 1a1c878 commit 3d38d46
Show file tree
Hide file tree
Showing 13 changed files with 210 additions and 86 deletions.
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -36,6 +36,7 @@
"lerna": "^3.0.0-rc.0", "lerna": "^3.0.0-rc.0",
"modular-css-core": "file:./packages/core", "modular-css-core": "file:./packages/core",
"pegjs": "^0.10.0", "pegjs": "^0.10.0",
"read-dir-deep": "^1.0.4",
"rollup": "^0.63.5", "rollup": "^0.63.5",
"rollup-plugin-svelte": "^4.2.1", "rollup-plugin-svelte": "^4.2.1",
"shelljs": "^0.8.1", "shelljs": "^0.8.1",
Expand Down
43 changes: 22 additions & 21 deletions packages/rollup/rollup.js
Expand Up @@ -177,18 +177,16 @@ module.exports = function(opts) {
} }


// First pass is used to calculate JS usage of CSS dependencies // First pass is used to calculate JS usage of CSS dependencies
Object.keys(bundles).forEach((entry) => { Object.entries(bundles).forEach(([ entry, bundle ]) => {
const file = makeFile({ const file = makeFile({
entry, entry,
css : [], css : new Set(),
}); });


// Get CSS files being used by each entry point const { modules } = bundle;
const css = Object.keys(bundles[entry].modules).filter(filter);


if(!css.length) { // Get CSS files being used by each entry point
return; const css = Object.keys(modules).filter(filter);
}


// Get dependency chains for each file // Get dependency chains for each file
css.forEach((start) => { css.forEach((start) => {
Expand All @@ -197,10 +195,14 @@ module.exports = function(opts) {
start, start,
]; ];


file.css.push(...used);

used.forEach((dep) => { used.forEach((dep) => {
usage.set(dep, (usage.get(dep) || 0) + 1); file.css.add(dep);

if(!usage.has(dep)) {
usage.set(dep, new Set());
}

usage.get(dep).add(entry);
}); });
}); });


Expand All @@ -209,22 +211,22 @@ module.exports = function(opts) {


if(files.length === 1) { if(files.length === 1) {
// Only one entry file means we only need one bundle. // Only one entry file means we only need one bundle.
files[0].css = processor.dependencies(); files[0].css = new Set(processor.dependencies());
} else { } else {
// Multiple bundles means ref-counting to find the shared deps // Multiple bundles means ref-counting to find the shared deps
// Second pass removes any dependencies appearing in multiple bundles // Second pass removes any dependencies appearing in multiple bundles
files.forEach((file) => { files.forEach((file) => {
const { css } = file; const { css } = file;


file.css = css.filter((dep) => { file.css = new Set([ ...css ].filter((dep) => {
if(usage.get(dep) > 1) { if(usage.get(dep).size > 1) {
common.set(dep, true); common.set(dep, true);


return false; return false;
} }


return true; return true;
}); }));
}); });


// Add any other files that weren't part of a bundle to the common chunk // Add any other files that weren't part of a bundle to the common chunk
Expand All @@ -238,25 +240,24 @@ module.exports = function(opts) {
if(common.size) { if(common.size) {
files.push(makeFile({ files.push(makeFile({
entry : options.common, entry : options.common,
css : [ ...common.keys() ], css : new Set([ ...common.keys() ]),
})); }));
} }
} }

await Promise.all( await Promise.all(
files files
.filter(({ css }) => css.length) .filter(({ css }) => css.size)
.map(async (details) => { .map(async ({ base, name, css }) => {
const { base, name, css } = details;
const id = this.emitAsset(`${base}.css`); const id = this.emitAsset(`${base}.css`);


const result = await processor.output({ const result = await processor.output({
to : to.replace(/\[(name|extname)\]/g, (match, field) => to : to.replace(/\[(name|extname)\]/g, (match, field) =>
(field === "name" ? name : ".css") (field === "name" ? name : ".css")
), ),
files : css, files : [ ...css ],
}); });

this.setAssetSource(id, result.css); this.setAssetSource(id, result.css);


if(options.json) { if(options.json) {
Expand Down
153 changes: 102 additions & 51 deletions packages/rollup/test/__snapshots__/splitting.test.js.snap
@@ -1,115 +1,166 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP


exports[`/rollup.js code splitting should support dynamic imports 1`] = ` exports[`/rollup.js code splitting should support dynamic imports 1`] = `
"/* packages/rollup/test/specimens/dynamic-imports/a.css */ Array [
Object {
"file": "a.css",
"text": "/* packages/rollup/test/specimens/dynamic-imports/a.css */
.a { .a {
color: aqua; color: aqua;
} }
" ",
`; },

Object {
exports[`/rollup.js code splitting should support dynamic imports 2`] = ` "file": "b.css",
"/* packages/rollup/test/specimens/dynamic-imports/b.css */ "text": "/* packages/rollup/test/specimens/dynamic-imports/b.css */
.b { .b {
color: blue; color: blue;
} }
" ",
`; },

Object {
exports[`/rollup.js code splitting should support dynamic imports 3`] = ` "file": "c.css",
"/* packages/rollup/test/specimens/dynamic-imports/c.css */ "text": "/* packages/rollup/test/specimens/dynamic-imports/c.css */
.c { .c {
color: cyan; color: cyan;
} }
" ",
`; },

Object {
exports[`/rollup.js code splitting should support dynamic imports 4`] = ` "file": "common.css",
"/* packages/rollup/test/specimens/dynamic-imports/d.css */ "text": "/* packages/rollup/test/specimens/dynamic-imports/d.css */
.d { .d {
color: darkred; color: darkred;
} }
" ",
},
]
`; `;


exports[`/rollup.js code splitting should support manual chunks 1`] = ` exports[`/rollup.js code splitting should support manual chunks 1`] = `
"/* packages/rollup/test/specimens/manual-chunks/a.css */ Array [
Object {
"file": "a.css",
"text": "/* packages/rollup/test/specimens/manual-chunks/a.css */
.a { .a {
color: red; color: red;
} }
" ",
`; },

Object {
exports[`/rollup.js code splitting should support manual chunks 2`] = ` "file": "b.css",
"/* packages/rollup/test/specimens/manual-chunks/b.css */ "text": "/* packages/rollup/test/specimens/manual-chunks/b.css */
.b { .b {
color: blue; color: blue;
} }
" ",
`; },

Object {
exports[`/rollup.js code splitting should support manual chunks 3`] = ` "file": "common.css",
"/* packages/rollup/test/specimens/manual-chunks/d.css */ "text": "/* packages/rollup/test/specimens/manual-chunks/d.css */
/* packages/rollup/test/specimens/manual-chunks/c.css */ /* packages/rollup/test/specimens/manual-chunks/c.css */
.c { .c {
color: green; color: green;
background: darkred; background: darkred;
} }
" ",
},
]
`; `;


exports[`/rollup.js code splitting should support splitting up CSS files 1`] = ` exports[`/rollup.js code splitting should support splitting up CSS files 1`] = `
"/* packages/rollup/test/specimens/simple.css */ Array [
Object {
"file": "common.css",
"text": "/* packages/rollup/test/specimens/simple.css */
.fooga { .fooga {
color: red; color: red;
} }
" ",
`; },

Object {
exports[`/rollup.js code splitting should support splitting up CSS files 2`] = ` "file": "dependencies.css",
"/* packages/rollup/test/specimens/dependencies.css */ "text": "/* packages/rollup/test/specimens/dependencies.css */
.wooga { .wooga {
background: blue; background: blue;
} }
" ",
},
]
`; `;


exports[`/rollup.js code splitting should support splitting up CSS files w/ shared assets 1`] = ` exports[`/rollup.js code splitting should support splitting up CSS files w/ shared assets 1`] = `
"/* packages/rollup/test/specimens/css-chunks/a.css */ Array [
Object {
"file": "a.css",
"text": "/* packages/rollup/test/specimens/css-chunks/a.css */
.a { .a {
color: aqua; color: aqua;
} }
" ",
`; },

Object {
exports[`/rollup.js code splitting should support splitting up CSS files w/ shared assets 2`] = ` "file": "b.css",
"/* packages/rollup/test/specimens/css-chunks/b.css */ "text": "/* packages/rollup/test/specimens/css-chunks/b.css */
.b { .b {
color: blue; color: blue;
} }
" ",
`; },

Object {
exports[`/rollup.js code splitting should support splitting up CSS files w/ shared assets 3`] = ` "file": "chunk.css",
"/* packages/rollup/test/specimens/css-chunks/c.css */ "text": "/* packages/rollup/test/specimens/css-chunks/c.css */
.c { .c {
color: cyan; color: cyan;
} }
" ",
},
Object {
"file": "common.css",
"text": "/* packages/rollup/test/specimens/css-chunks/shared.css */
.shared {
color: snow;
}
",
},
]
`; `;


exports[`/rollup.js code splitting should support splitting up CSS files w/ shared assets 4`] = ` exports[`/rollup.js code splitting shouldn't put bundle-specific CSS in common.css 1`] = `
"/* packages/rollup/test/specimens/css-chunks/shared.css */ Array [
Object {
"file": "a.css",
"text": "/* packages/rollup/test/specimens/common-splitting/shared.css */
.shared { .shared {
color: snow; color: snow;
} }
" /* packages/rollup/test/specimens/common-splitting/a.css */
.a {
color: aqua;
}
/* packages/rollup/test/specimens/common-splitting/b.css */
.b {
color: blue;
}
",
},
Object {
"file": "c.css",
"text": "/* packages/rollup/test/specimens/common-splitting/c.css */
.c {
color: cyan;
}
",
},
]
`; `;
5 changes: 5 additions & 0 deletions packages/rollup/test/specimens/common-splitting/a.css
@@ -0,0 +1,5 @@
.a {
composes: shared from "./shared.css";

color: aqua;
}
4 changes: 4 additions & 0 deletions packages/rollup/test/specimens/common-splitting/a.js
@@ -0,0 +1,4 @@
import css from "./a.css";
import js from "./b.js";

console.log(css, js);
5 changes: 5 additions & 0 deletions packages/rollup/test/specimens/common-splitting/b.css
@@ -0,0 +1,5 @@
.b {
composes: shared from "./shared.css";

color: blue;
}
5 changes: 5 additions & 0 deletions packages/rollup/test/specimens/common-splitting/b.js
@@ -0,0 +1,5 @@
import css from "./b.css";

console.log(css);

export default "b.js";
3 changes: 3 additions & 0 deletions packages/rollup/test/specimens/common-splitting/c.css
@@ -0,0 +1,3 @@
.c {
color: cyan;
}
3 changes: 3 additions & 0 deletions packages/rollup/test/specimens/common-splitting/c.js
@@ -0,0 +1,3 @@
import css from "./c.css";

export default css;
3 changes: 3 additions & 0 deletions packages/rollup/test/specimens/common-splitting/shared.css
@@ -0,0 +1,3 @@
.shared {
color: snow;
}

0 comments on commit 3d38d46

Please sign in to comment.