Skip to content

Commit e3fd6f2

Browse files
committed
feat: Invalidate handlebar template caches when dependent blocks change.
1 parent b6163ad commit e3fd6f2

File tree

4 files changed

+440
-130
lines changed

4 files changed

+440
-130
lines changed

packages/@css-blocks/ember-cli/index.js

+28-6
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,9 @@ module.exports = {
102102
registry.add("htmlbars-ast-plugin", {
103103
name: "css-blocks-htmlbars",
104104
plugin: this.astPlugin.bind(this),
105-
// cacheKey: () => {
106-
// return this.transports.get(this.parent).mapping;
107-
// }
105+
dependencyInvalidation: true,
106+
cacheKey: () => this.optionsForCacheInvalidation(),
107+
baseDir: () => __dirname,
108108
});
109109

110110
// For Glimmer
@@ -267,9 +267,10 @@ module.exports = {
267267
options.aliases || (options.aliases = {});
268268
options.analysisOpts || (options.analysisOpts = {});
269269
options.optimization || (options.optimization = {});
270-
options.parserOpts || (options.parserOpts = {
271-
importer: new NodeJsImporter(options.aliases),
272-
});
270+
options.parserOpts || (options.parserOpts = {});
271+
272+
// Use the node importer by default.
273+
options.parserOpts.importer = options.parserOpts.importer || new NodeJsImporter(options.aliases);
273274

274275
// Optimization is always disabled for now, until we get project-wide analysis working.
275276
options.optimization.enabled = false;
@@ -292,6 +293,27 @@ module.exports = {
292293
return options;
293294
},
294295

296+
optionsForCacheInvalidation() {
297+
let aliases = this._options.aliases;
298+
let analysisOpts = this._options.analysisOpts;
299+
let optimization = this._options.optimization;
300+
let parserOpts = {};
301+
Object.assign(parserOpts, this._options.parserOpts);
302+
let constructor = parserOpts.importer && parserOpts.importer.constructor;
303+
if (constructor) {
304+
parserOpts.importer = constructor.name;
305+
} else {
306+
delete parserOpts.importer;
307+
}
308+
309+
return {
310+
aliases,
311+
analysisOpts,
312+
optimization,
313+
parserOpts
314+
};
315+
},
316+
295317
genTreeWrapper(env, options, prev = NOOP) {
296318
const { isEmber, app, parent, rootDir, moduleConfig, modulePrefix } = env;
297319

packages/@css-blocks/ember-cli/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,16 @@
3030
"broccoli-merge-trees": "^3.0.2",
3131
"debug": "^4.1.1",
3232
"ember-cli-babel": "7.11.0",
33-
"ember-cli-htmlbars": "^3.0.0",
3433
"fs-extra": "^8.0.0",
3534
"symlink-or-copy": "^1.2.0"
3635
},
3736
"devDependencies": {
37+
"@ember/jquery": "^0.6.1",
3838
"broccoli-asset-rev": "^3.0.0",
3939
"ember-ajax": "^5.0.0",
4040
"ember-cli": "~3.11",
4141
"ember-cli-eslint": "^5.1.0",
42+
"ember-cli-htmlbars": "^3.1.0",
4243
"ember-cli-htmlbars-inline-precompile": "^2.1.0",
4344
"ember-cli-inject-live-reload": "^2.0.1",
4445
"ember-cli-qunit": "^4.3.2",

packages/@css-blocks/glimmer/src/Rewriter.ts

+55-10
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,34 @@ const DEBUG = debugGenerator("css-blocks:glimmer:rewriter");
2626

2727
export type GlimmerStyleMapping = StyleMapping<TEMPLATE_TYPE>;
2828

29-
export class GlimmerRewriter implements ASTPlugin {
29+
interface ASTPluginWithDeps extends ASTPlugin {
30+
/**
31+
* If this method exists, it is called with the relative path to the current
32+
* file just before processing starts. Use this method to reset the
33+
* dependency tracking state associated with the file.
34+
*/
35+
resetDependencies?(relativePath: string): void;
36+
/**
37+
* This method is called just as the template finishes being processed.
38+
*
39+
* @param relativePath A relative path to the file that may have dependencies.
40+
* @return paths to files that are a dependency for the given
41+
* file. Any relative paths returned by this method are taken to be relative
42+
* to the file that was processed.
43+
*/
44+
dependencies(relativePath: string): string[];
45+
}
46+
47+
export class GlimmerRewriter implements ASTPluginWithDeps {
3048
template: ResolvedFile;
3149
analysis: GlimmerAnalysis;
3250
elementCount: number;
3351
syntax: Syntax;
3452
block: Block;
3553
styleMapping: GlimmerStyleMapping;
3654
cssBlocksOpts: CSSBlocksConfiguration;
55+
visitor: NodeVisitor;
56+
visitors: NodeVisitor;
3757

3858
private elementAnalyzer: ElementAnalyzer;
3959

@@ -51,6 +71,16 @@ export class GlimmerRewriter implements ASTPlugin {
5171
this.cssBlocksOpts = resolveConfiguration(cssBlocksOpts);
5272
this.elementCount = 0;
5373
this.elementAnalyzer = new ElementAnalyzer(this.analysis, this.cssBlocksOpts);
74+
if (this.block) {
75+
this.visitor = {
76+
ElementNode: this.ElementNode.bind(this),
77+
MustacheStatement: this.BuiltinStatement.bind(this),
78+
BlockStatement: this.BuiltinStatement.bind(this),
79+
};
80+
} else {
81+
this.visitor = {};
82+
}
83+
this.visitors = this.visitor;
5484
}
5585

5686
debug(message: string, ...args: unknown[]): void {
@@ -59,15 +89,30 @@ export class GlimmerRewriter implements ASTPlugin {
5989

6090
get name(): string { return this.block ? "css-blocks-glimmer-rewriter" : "css-blocks-noop"; }
6191

62-
// `visitors` is used by Ember < 3.0.0. `visitor` is used by Glimmer and Ember >= 3.0.0.
63-
get visitor(): NodeVisitor { return this.visitors; }
64-
get visitors(): NodeVisitor {
65-
if (!this.block) { return {}; }
66-
return {
67-
ElementNode: this.ElementNode.bind(this),
68-
MustacheStatement: this.BuiltinStatement.bind(this),
69-
BlockStatement: this.BuiltinStatement.bind(this),
70-
};
92+
/**
93+
* @param _relativePath Unused in this implementation.
94+
* @returns Files this template file depends on.
95+
*/
96+
dependencies(_relativePath: string): Array<string> {
97+
this.debug("Getting dependencies for", _relativePath);
98+
let deps: Set<string> = new Set();
99+
100+
// let importer = this.cssBlocksOpts.importer;
101+
for (let block of this.analysis.transitiveBlockDependencies()) {
102+
// TODO: Figure out why the importer is returning null here.
103+
// let blockFile = importer.filesystemPath(block.identifier, this.cssBlocksOpts);
104+
let blockFile = block.identifier;
105+
this.debug("block file path is", blockFile);
106+
if (blockFile) {
107+
deps.add(blockFile);
108+
}
109+
// These dependencies happen when additional files get involved via preprocessors.
110+
for (let additionalDep of block.dependencies) {
111+
deps.add(additionalDep);
112+
}
113+
}
114+
let depArray = new Array(...deps);
115+
return depArray;
71116
}
72117

73118
BuiltinStatement(node: AST.MustacheStatement | AST.BlockStatement) {

0 commit comments

Comments
 (0)