Skip to content

Commit 3e7fae3

Browse files
committed
ensured deterministic manifest serialization
this avoids meaningless file changes due to random insertion order
1 parent b880ae9 commit 3e7fae3

File tree

3 files changed

+54
-8
lines changed

3 files changed

+54
-8
lines changed

lib/manifest.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ let { abort } = require("./util");
66
let path = require("path");
77

88
module.exports = class Manifest {
9-
constructor(referenceDir, { target, key, value, baseURI, webRoot }) {
9+
constructor(referenceDir, { target, key, value, baseURI, webRoot } = {}) {
1010
if(target) {
1111
this.filepath = resolvePath(target, referenceDir, {
1212
enforceRelative: true
1313
});
1414
}
15-
this._index = {};
15+
this._index = new Map();
1616

1717
if(key === "short") {
1818
this.keyTransform = (fp, targetDir) => path.relative(targetDir, fp);
@@ -34,19 +34,24 @@ module.exports = class Manifest {
3434
}
3535

3636
get(originalPath) {
37-
return this._index[originalPath];
37+
return this._index.get(originalPath);
3838
}
3939

4040
set(originalPath, actualPath, targetDir) {
4141
let key = this.keyTransform(originalPath, targetDir);
4242
let uri = this.valueTransform(actualPath);
43-
this._index[key] = uri;
43+
this._index.set(key, uri);
4444

4545
let fp = this.filepath;
4646
return fp ? createFile(fp, this.toJSON()) : Promise.resolve(null);
4747
}
4848

4949
toJSON() {
50-
return JSON.stringify(this._index) + "\n";
50+
let index = this._index;
51+
let manifest = Array.from(index.keys()).sort().reduce((memo, key) => {
52+
memo[key] = index.get(key);
53+
return memo;
54+
}, {});
55+
return JSON.stringify(manifest) + "\n";
5156
}
5257
};

test/test_manager.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,19 @@ let assert = require("assert");
88
let assertSame = assert.strictEqual;
99

1010
describe("asset manager", _ => {
11+
let root = path.resolve(__dirname, "fixtures");
1112
let cwd;
1213

1314
before(() => {
1415
cwd = process.cwd();
16+
process.chdir(root);
1517
});
1618

1719
after(() => {
1820
process.chdir(cwd);
1921
});
2022

2123
it("resolves file paths for local modules and third-party packages", () => {
22-
let root = path.resolve(__dirname, "fixtures");
23-
process.chdir(root);
24-
2524
let { resolvePath } = new AssetManager(root);
2625

2726
let filepath = resolvePath("dummy/src.js");

test/test_manifest.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* global describe, before, after, it */
2+
"use strict";
3+
4+
let Manifest = require("../lib/manifest");
5+
let path = require("path");
6+
let assert = require("assert");
7+
8+
let assertSame = assert.strictEqual;
9+
10+
describe("manifest", _ => {
11+
let root = path.resolve(__dirname, "fixtures");
12+
let cwd;
13+
14+
before(() => {
15+
cwd = process.cwd();
16+
process.chdir(root);
17+
});
18+
19+
after(() => {
20+
process.chdir(cwd);
21+
});
22+
23+
it("maps original to actual file names with deterministic serialization", () => {
24+
let manifest = new Manifest(root);
25+
return manifest.set("foo.png", "foo-abc123.png").
26+
then(_ => { // eslint-disable-next-line quotes
27+
assertSame(manifest.toJSON(), `{"foo.png":"/foo-abc123.png"}\n`);
28+
29+
return manifest.set("bar.css", "bar-def456.css");
30+
}).
31+
then(_ => {
32+
assertSame(manifest.toJSON(), // eslint-disable-next-line quotes
33+
`{"bar.css":"/bar-def456.css","foo.png":"/foo-abc123.png"}\n`);
34+
35+
return manifest.set("xox.js", "xox-ghi789.js");
36+
}).
37+
then(_ => {
38+
assertSame(manifest.toJSON(), // eslint-disable-next-line quotes
39+
`{"bar.css":"/bar-def456.css","foo.png":"/foo-abc123.png","xox.js":"/xox-ghi789.js"}\n`);
40+
});
41+
});
42+
});

0 commit comments

Comments
 (0)