Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial implementation of co-located templates RFC. #249

Merged
merged 34 commits into from
Sep 24, 2019
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
fbda2e0
Initial spike of co-located templates RFC.
chancancode May 9, 2019
764615e
Use globals for now
chancancode Aug 10, 2019
a640658
Fix addon compilation
chancancode Aug 12, 2019
4c6017b
Better error for missing default export
chancancode Aug 13, 2019
942c301
v3.2.0-alpha.0
chancancode Aug 22, 2019
66dff2f
Fix some Node 8 issues
chancancode Aug 24, 2019
b9295c5
Fix lint
chancancode Aug 24, 2019
6b5a4d6
Extract ColocatedTemplateProcessor to dedicated file.
rwjblue Sep 5, 2019
10e5f31
Merge remote-tracking branch 'origin/master' into colocation
rwjblue Sep 5, 2019
3aabb50
Update linting config to allow async functions.
rwjblue Sep 5, 2019
d7a579b
Add broccoli-debug logging.
rwjblue Sep 5, 2019
f7f3f47
Start fleshing out basic testing infrastructure.
rwjblue Sep 5, 2019
1dbfb87
Merge remote-tracking branch 'origin/master' into colocation
rwjblue Sep 5, 2019
6ba80f4
Merge remote-tracking branch 'origin/master' into colocation
rwjblue Sep 9, 2019
24e8ad6
yarn lint:js --fix
rwjblue Sep 9, 2019
fb2808a
Extract helper method to build merged component JS contents.
rwjblue Sep 5, 2019
f5a0b01
Add TODO comments for additional tasks.
rwjblue Sep 6, 2019
6de52e5
Flesh out more tests.
rwjblue Sep 6, 2019
5709c0f
Avoid adding the import for setComponentTemplate.
rwjblue Sep 6, 2019
b44e14b
yarn lint:js --fix
rwjblue Sep 9, 2019
bb4ad58
Fix colocated-broccoli-plugin tests
rwjblue Sep 9, 2019
9362a4c
Add babel plugin to add setComponentTemplate usage.
rwjblue Sep 9, 2019
952287b
Simplify implementation / reduce duplication.
rwjblue Sep 9, 2019
cfa93e3
Make requires more lazy.
rwjblue Sep 9, 2019
eba43a7
Add proper guard for using colocation.
rwjblue Sep 9, 2019
99ac97d
Refactor registry toTree setup.
rwjblue Sep 9, 2019
60b8ae9
Tweak comments in colocated-broccoli-plugin.
rwjblue Sep 9, 2019
2d58f11
Ensure debugTree's are not "merged" for different invocations.
rwjblue Sep 9, 2019
9972294
Add tests for scoped addons.
rwjblue Sep 9, 2019
db7e5f2
Only process colocated files from <app-or-addon-name>/components/
rwjblue Sep 9, 2019
1ef7d42
Merge pull request #280 from rwjblue/colocation-refactor
rwjblue Sep 14, 2019
791bde4
Fix setComponentTemplate argument ordering for native classes.
rwjblue Sep 14, 2019
253503f
Only opt-in to colocation when using octane edition.
rwjblue Sep 15, 2019
35b66bf
Merge remote-tracking branch 'origin/master' into colocation
rwjblue Sep 23, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module.exports = {
root: true,
parserOptions: {
ecmaVersion: 2017,
ecmaVersion: 2018,
sourceType: 'module'
},
plugins: [
Expand All @@ -22,6 +22,7 @@ module.exports = {
{
files: [
'.template-lintrc.js',
'colocated-broccoli-plugin.js',
'ember-cli-build.js',
'ember-addon-main.js',
'index.js',
Expand All @@ -40,7 +41,7 @@ module.exports = {
],
parserOptions: {
sourceType: 'script',
ecmaVersion: 2015
ecmaVersion: 2018
},
env: {
browser: false,
Expand All @@ -59,7 +60,7 @@ module.exports = {
],
parserOptions: {
sourceType: 'script',
ecmaVersion: 2015
ecmaVersion: 2018
},
env: {
browser: false,
Expand Down
104 changes: 104 additions & 0 deletions colocated-broccoli-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
'use strict';

const fs = require('fs');
const mkdirp = require('mkdirp');
const copyFileSync = require('fs-copy-file-sync');
const path = require('path');
const walkSync = require('walk-sync');
const Plugin = require('broccoli-plugin');

module.exports = class ColocatedTemplateProcessor extends Plugin {
constructor(tree, options) {
super([tree], options);

this.options = options;
}

build() {
// TODO: do we need to pass through all files, or only template files?
let files = walkSync(this.inputPaths[0], { directories: false });

let filesToCopy = [];
files.forEach(filePath => {
let filePathParts = path.parse(filePath);
let inputPath = path.join(this.inputPaths[0], filePath);

// TODO: why are these different?
// Apps: my-app/components/foo.hbs, my-app/templates/components/foo.hbs
// Addons: components/foo.js, templates/components/foo.hbs

// TODO: make this more robust
let isInsideComponentsFolder =
(filePath.includes('/components/') || filePath.startsWith('components/')) &&
!filePath.includes('/templates/components/') &&
!filePath.startsWith('templates/components');

// copy forward non-hbs files
// TODO: don't copy .js files that will ultimately be overridden
if (!isInsideComponentsFolder || filePathParts.ext !== '.hbs') {
filesToCopy.push(filePath);
return;
}

// TODO: deal with alternate extensions (e.g. ts)
let possibleJSPath = path.join(filePathParts.dir, filePathParts.name + '.js');
let hasJSFile = fs.existsSync(path.join(this.inputPaths[0], possibleJSPath));

if (filePathParts.name === 'template') {
// TODO: maybe warn?
return;
}

let templateContents = fs.readFileSync(inputPath, { encoding: 'utf8' });
let jsContents = null;

// TODO: deal with hygiene
if (hasJSFile) {
// add the template, call setComponentTemplate

jsContents = fs.readFileSync(path.join(this.inputPaths[0], possibleJSPath), { encoding: 'utf8' });

if (jsContents.includes('export default')) {
jsContents = jsContents.replace('export default', 'const CLASS =');
} else {
let message = `${filePath}\` does not contain a \`default export\`. Did you forget to export the component class?`;
jsContents = `${jsContents}\nthrow new Error(${JSON.stringify(message)})`;
}

jsContents = `${jsContents}
const setComponentTemplate = Ember._setComponentTemplate;
const TEMPLATE = ${this.options.precompile(templateContents)};
export default setComponentTemplate(TEMPLATE, CLASS);`;
} else {
// create JS file, use null component pattern
jsContents = `const templateOnlyComponent = Ember._templateOnlyComponent;
const setComponentTemplate = Ember._setComponentTemplate;
const TEMPLATE = ${this.options.precompile(templateContents)};
const CLASS = templateOnlyComponent();
export default setComponentTemplate(TEMPLATE, CLASS);`;
}


let outputPath = path.join(this.outputPath, possibleJSPath);

// TODO: don't speculatively mkdirSync (likely do in a try/catch with ENOENT)
mkdirp.sync(path.dirname(outputPath));
fs.writeFileSync(outputPath, jsContents, { encoding: 'utf8' });
});

filesToCopy.forEach(filePath => {
let inputPath = path.join(this.inputPaths[0], filePath);
let outputPath = path.join(this.outputPath, filePath);

// avoid copying file over top of a previously written one
if (fs.existsSync(outputPath)) {
return;
}

// TODO: don't speculatively mkdirSync (likely do in a try/catch with ENOENT)
mkdirp.sync(path.dirname(outputPath));
copyFileSync(inputPath, outputPath);
})
}
}

32 changes: 26 additions & 6 deletions ember-addon-main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,24 @@ const path = require('path');
const utils = require('./utils');
const addDependencyTracker = require("./addDependencyTracker");
const hashForDep = require('hash-for-dep');
const ColocatedTemplateProcessor = require('./colocated-broccoli-plugin');

module.exports = {
name: require('./package').name,

parentRegistry: null,

_getDebugTree() {
if (!this._cachedDebugTree) {
// when this.parent === this.project, `this.parent.name` is a function 😭
let parentName = typeof this.parent.name === 'function' ? this.parent.name() : this.parent.name;

this._cachedDebugTree = require('broccoli-debug').buildDebugCallback(`ember-cli-htmlbars:${parentName}`);
}

return this._cachedDebugTree;
},

purgeModule(templateCompilerPath) {
// ensure we get a fresh templateCompilerModuleInstance per ember-addon
// instance NOTE: this is a quick hack, and will only work as long as
Expand Down Expand Up @@ -37,21 +49,29 @@ module.exports = {
// ensure that broccoli-ember-hbs-template-compiler is not processing hbs files
registry.remove('template', 'broccoli-ember-hbs-template-compiler');

let precompile = string => {
let htmlbarsOptions = this.htmlbarsOptions();
let templateCompiler = htmlbarsOptions.templateCompiler;
return utils.template(templateCompiler, string);
}

let debugTree = this._getDebugTree();

registry.add('template', {
name: 'ember-cli-htmlbars',
ext: 'hbs',
_addon: this,
toTree(tree) {
let inputTree = debugTree(tree, '01-input');

let htmlbarsOptions = this._addon.htmlbarsOptions();
let unifiedColocatedTemplates = debugTree(new ColocatedTemplateProcessor(inputTree, { precompile }), '02-colocated-output');

let TemplateCompiler = require('./index');
return new TemplateCompiler(tree, htmlbarsOptions);
return debugTree(new TemplateCompiler(unifiedColocatedTemplates, htmlbarsOptions), '03-output');
},

precompile(string) {
let htmlbarsOptions = this._addon.htmlbarsOptions();
let templateCompiler = htmlbarsOptions.templateCompiler;
return utils.template(templateCompiler, string);
}
precompile,
});

if (type === 'parent') {
Expand Down
14 changes: 10 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ember-cli-htmlbars",
"version": "3.1.0",
"version": "3.2.0-alpha.0",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to tweak this, as there are breaking changes now on master.

"description": "A library for adding htmlbars to ember CLI",
"keywords": [
"ember-addon",
Expand All @@ -17,9 +17,10 @@
"license": "MIT",
"author": "Jonathan Jackson & Chase McCarthy",
"files": [
"index.js",
"addDependencyTracker.js",
"colocated-broccoli-plugin.js",
"ember-addon-main.js",
"index.js",
"utils.js"
],
"main": "index.js",
Expand All @@ -34,17 +35,22 @@
"test:node:debug": "mocha debug node-tests/*.js"
},
"dependencies": {
"broccoli-debug": "^0.6.5",
"broccoli-persistent-filter": "^2.3.1",
"broccoli-plugin": "^2.0.0",
"fs-copy-file-sync": "^1.1.1",
"hash-for-dep": "^1.5.1",
"json-stable-stringify": "^1.0.1",
"strip-bom": "^3.0.0"
"mkdirp": "^0.5.1",
"strip-bom": "^3.0.0",
"walk-sync": "^1.1.3"
},
"devDependencies": {
"@ember/optional-features": "^0.7.0",
"broccoli-test-helper": "^2.0.0",
"chai": "^4.2.0",
"co": "^4.6.0",
"ember-cli": "~3.9.0",
"ember-cli": "github:ember-cli/ember-cli",
rwjblue marked this conversation as resolved.
Show resolved Hide resolved
"ember-cli-app-version": "^3.2.0",
"ember-cli-babel": "^7.11.0",
"ember-cli-dependency-checker": "^3.2.0",
Expand Down
1 change: 1 addition & 0 deletions tests/dummy/app/components/bar.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello from bar!
5 changes: 5 additions & 0 deletions tests/dummy/app/components/bar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Component from '@ember/component';

export default Component.extend({
attributeBindings: ['lolol'],
});
1 change: 1 addition & 0 deletions tests/dummy/app/components/foo.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Stuff!!
Empty file.
Loading