Skip to content
Permalink
Browse files

feat: add metadata output option (#542)

* feat: add meta option to rollup

Outputs a JSON file containing the CSS dependencies for each JS entry point.

* fix: bring back common.css

BREAKING CHANGE:

The previous release would stick all unreferenced CSS at the beginning of the first bundle. This was a mistake, and has been rectified.
  • Loading branch information...
tivac committed Jan 18, 2019
1 parent b8dce99 commit e42e99737086fca4a72ecc461d9a422a86d06217
@@ -80,6 +80,12 @@ Boolean to determine if inline source maps should be included. Defaults to `true

To force the creation of external source maps set the value to `{ inline : false }`.

### `meta`

Boolean/String to determine if chunk metadata should be output. If set to true will write out a file named `metadata.json`. If a `String` will write out to that file name. Defaults to `false`.

Currently the only metadata being written is CSS dependencies, but that may change in the future.

### `namedExports`

By default this plugin will create both a default export and named `export`s for each class in a CSS file. You can disable this by setting `namedExports` to `false`.
@@ -23,12 +23,13 @@ const emptyMappings = {

module.exports = (opts) => {
const options = Object.assign(Object.create(null), {
common : "common",
json : false,
common : "common.css",
dev : false,
include : "**/*.css",
json : false,
meta : false,
namedExports : true,
styleExport : false,
dev : false,
verbose : false,
}, opts);

@@ -189,7 +190,7 @@ module.exports = (opts) => {
});

// Output CSS chunks
const out = [];
const out = new Map();

// Keep track of files that are queued to be written
const queued = new Set();
@@ -230,10 +231,11 @@ module.exports = (opts) => {
dest = outputOptions.dir ? name : path.basename(entry, path.extname(entry));
}

out.push([
dest,
included,
]);
out.set(entry, {
name : dest,
files : included,
dependencies : usage.dependenciesOf(entry),
});

// Flag all the files that are queued for writing so they don't get double-output
css.forEach((file) => queued.add(file));
@@ -254,14 +256,12 @@ module.exports = (opts) => {

// Shove any unreferenced CSS files onto the beginning of the first chunk
if(unused.length) {
if(out.length) {
out[0][1].unshift(...unused);
} else {
out.push([
common,
unused
]);
}
out.set("unused", {
// Add .css automatically down below, so strip in case it was specified
name : common.replace(path.extname(common), ""),
files : unused,
dependencies : false
});
}

// If assets are being hashed then the automatic annotation has to be disabled
@@ -276,7 +276,9 @@ module.exports = (opts) => {
);
}

for(const [ name, files ] of out) {
for(const [ entry, value ] of out.entries()) {
const { name, files } = value;

const id = this.emitAsset(`${name}.css`);

/* eslint-disable-next-line no-await-in-loop */
@@ -293,20 +295,25 @@ module.exports = (opts) => {

this.setAssetSource(id, result.css);

const dest = this.getAssetFileName(id);

// Update output data with the resulting filename from rollup
out.set(entry, Object.assign(value, {
dest,
}));

// Maps can't be written out via the asset APIs becuase they shouldn't ever be hashed.
// They shouldn't be hashed because they simply follow the name of their parent .css asset.
// So push them onto an array and write them out in the writeBundle hook below
if(result.map) {
const file = this.getAssetFileName(id);

maps.push({
to,
file,
file : dest,
content : result.map
});
}
}

if(options.json) {
const dest = typeof options.json === "string" ? options.json : "exports.json";

@@ -316,6 +323,22 @@ module.exports = (opts) => {

this.emitAsset(dest, JSON.stringify(compositions, null, 4));
}

if(options.meta) {
const dest = typeof options.meta === "string" ? options.meta : "metadata.json";

log("metadata output", dest);

const meta = {};

out.forEach(({ dest : file, dependencies }, entry) => {
meta[entry] = {
dependencies : [ file, ...dependencies.map((key) => out.get(key).dest) ]
};
});

this.emitAsset(dest, JSON.stringify(meta, null, 4));
}
},

writeBundle() {
@@ -29,21 +29,35 @@ console.log({ foo: foo$1, bar: bar$3, bar2: bar$1 });
`;

exports[`/rollup.js should accept an existing processor instance (no css in bundle) 1`] = `
"/* packages/rollup/test/specimens/fake.css */
Array [
Object {
"file": "common.css",
"text": "/* packages/rollup/test/specimens/fake.css */
.fake {
color: yellow;
}"
}",
},
]
`;

exports[`/rollup.js should accept an existing processor instance 1`] = `
"/* packages/rollup/test/specimens/fake.css */
Array [
Object {
"file": "common.css",
"text": "/* packages/rollup/test/specimens/fake.css */
.fake {
color: yellow;
}
/* packages/rollup/test/specimens/simple.css */
}",
},
Object {
"file": "existing-processor.css",
"text": "/* packages/rollup/test/specimens/simple.css */
.fooga {
color: red;
}"
}
",
},
]
`;

exports[`/rollup.js should allow disabling of named exports 1`] = `
@@ -428,6 +442,26 @@ exports[`/rollup.js should respect the CSS dependency tree 2`] = `
"
`;

exports[`/rollup.js should use the common arg for unreferenced CSS 1`] = `
Array [
Object {
"file": "simple.css",
"text": "/* packages/rollup/test/specimens/simple.css */
.fooga {
color: red;
}
",
},
Object {
"file": "unreferenced.css",
"text": "/* packages/rollup/test/specimens/fake.css */
.fake {
color: yellow;
}",
},
]
`;

exports[`/rollup.js should warn & not export individual keys when they are not valid identifiers 1`] = `
Object {
"code": "PLUGIN_WARNING",
@@ -301,6 +301,44 @@ Array [
]
`;

exports[`/rollup.js code splitting should support outputting metadata about CSS dependencies 1`] = `
Array [
Object {
"file": "chunk.css",
"text": "/* packages/rollup/test/specimens/simple.css */
.fooga {
color: red;
}
",
},
Object {
"file": "dependencies.css",
"text": "/* packages/rollup/test/specimens/dependencies.css */
.wooga {

background: blue;
}
",
},
Object {
"file": "metadata.json",
"text": "{
\\"chunk.js\\": {
\\"dependencies\\": [
\\"assets/chunk.css\\"
]
},
\\"dependencies.js\\": {
\\"dependencies\\": [
\\"assets/dependencies.css\\",
\\"assets/chunk.css\\"
]
}
}",
},
]
`;

exports[`/rollup.js code splitting should support splitting up CSS files 1`] = `
Array [
Object {
@@ -10,6 +10,7 @@ const read = require("@modular-css/test-utils/read.js")(__dirname);
const readdir = require("@modular-css/test-utils/read-dir.js")(__dirname);
const exists = require("@modular-css/test-utils/exists.js")(__dirname);
const prefix = require("@modular-css/test-utils/prefix.js")(__dirname);
const dir = require("@modular-css/test-utils/read-dir.js")(__dirname);
const namer = require("@modular-css/test-utils/namer.js");
const logs = require("@modular-css/test-utils/logs.js");

@@ -226,6 +227,38 @@ describe("/rollup.js", () => {
expect(read("./json-named/assets/custom.json")).toMatchSnapshot();
});

it("should use the common arg for unreferenced CSS", async () => {
const processor = new Processor({
namer,
map,
});

await processor.string("./packages/rollup/test/specimens/fake.css", dedent(`
.fake {
color: yellow;
}
`));

const bundle = await rollup({
input : require.resolve("./specimens/simple.js"),
plugins : [
plugin({
namer,
processor,
common : "unreferenced.css",
}),
],
});

await bundle.write({
format,
assetFileNames,
file : prefix(`./output/common-option/simple.js`),
});

expect(dir("./common-option/assets/")).toMatchSnapshot();
});

it("should provide named exports", async () => {
const bundle = await rollup({
input : require.resolve("./specimens/named.js"),
@@ -438,7 +471,7 @@ describe("/rollup.js", () => {
file : prefix(`./output/existing-processor/existing-processor.js`),
});

expect(read("./existing-processor/assets/existing-processor.css")).toMatchSnapshot();
expect(dir("./existing-processor/assets/")).toMatchSnapshot();
});

it("should accept an existing processor instance (no css in bundle)", async () => {
@@ -470,7 +503,7 @@ describe("/rollup.js", () => {
file : prefix(`./output/existing-processor-no-css/existing-processor-no-css.js`),
});

expect(read("./existing-processor-no-css/assets/common.css")).toMatchSnapshot();
expect(dir("./existing-processor-no-css/assets/")).toMatchSnapshot();
});

it("should output a proxy in dev mode", async () => {
@@ -55,6 +55,35 @@ describe("/rollup.js", () => {

expect(dir("./splitting/assets")).toMatchSnapshot();
});

it("should support outputting metadata about CSS dependencies", async () => {
const bundle = await rollup({
input : [
require.resolve("./specimens/simple.js"),
require.resolve("./specimens/dependencies.js"),
],

plugins : [
plugin({
namer,
map,
meta : true,
}),
],
});

await bundle.write({
format,
sourcemap,

assetFileNames,
chunkFileNames,

dir : prefix(`./output/css-metadata`),
});

expect(dir("./css-metadata/assets")).toMatchSnapshot();
});

it("should support splitting up CSS files w/ shared assets", async () => {
const bundle = await rollup({

0 comments on commit e42e997

Please sign in to comment.
You can’t perform that action at this time.