Skip to content

Commit

Permalink
Merge pull request #749 from ember-cli/always-use-babel
Browse files Browse the repository at this point in the history
Drive all template compilation from babel
  • Loading branch information
ef4 authored Jul 4, 2022
2 parents 8e2ba66 + a95a4fe commit 2f2cac9
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 781 deletions.
145 changes: 14 additions & 131 deletions lib/template-compiler-plugin.js
Original file line number Diff line number Diff line change
@@ -1,155 +1,38 @@
'use strict';

const path = require('path');
const utils = require('./utils');
const Filter = require('broccoli-persistent-filter');
const crypto = require('crypto');
const stringify = require('json-stable-stringify');
const stripBom = require('strip-bom');

function rethrowBuildError(error) {
if (!error) {
throw new Error('Unknown Error');
}

if (typeof error === 'string') {
throw new Error('[string exception]: ' + error);
} else {
// augment with location and type information and re-throw.
error.type = 'Template Compiler Error';
error.location = error.location && error.location.start;

throw error;
}
}
const jsStringEscape = require('js-string-escape');

class TemplateCompiler extends Filter {
constructor(inputTree, _options, requiresModuleApiPolyfill = true) {
let options = _options || {};

constructor(inputTree, options = {}) {
if (!('persist' in options)) {
options.persist = true;
}

super(inputTree, options);

this.options = options;
this.inputTree = inputTree;
this.requiresModuleApiPolyfill = requiresModuleApiPolyfill;

// TODO: do we need this?
this.precompile = this.options.templateCompiler.precompile;

let { templateCompiler, EmberENV } = options;

utils.initializeEmberENV(templateCompiler, EmberENV);
}

baseDir() {
return __dirname;
}

processString(string, relativePath) {
let srcDir = this.inputPaths[0];
let srcName = path.join(srcDir, relativePath);

try {
// we have to reverse these for reasons that are a bit bonkers. the initial
// version of this system used `registeredPlugin` from
// `ember-template-compiler.js` to set up these plugins (because Ember ~ 1.13
// only had `registerPlugin`, and there was no way to pass plugins directly
// to the call to `compile`/`precompile`). calling `registerPlugin`
// unfortunately **inverted** the order of plugins (it essentially did
// `PLUGINS = [plugin, ...PLUGINS]`).
//
// sooooooo...... we are forced to maintain that **absolutely bonkers** ordering
let astPlugins = this.options.plugins ? [...this.options.plugins.ast].reverse() : [];

let precompiled = this.options.templateCompiler.precompile(stripBom(string), {
contents: string,
isProduction: this.options.isProduction,
moduleName: relativePath,
parseOptions: {
srcName: srcName,
},

// intentionally not using `plugins: this.options.plugins` here
// because if we do, Ember will mutate the shared plugins object (adding
// all of the built in AST transforms into plugins.ast, which breaks
// persistent caching)
plugins: {
ast: astPlugins,
},
});

if (this.options.dependencyInvalidation) {
let plugins = pluginsWithDependencies(this.options.plugins.ast);
let dependencies = [];
for (let i = 0; i < plugins.length; i++) {
let pluginDeps = plugins[i].getDependencies(relativePath);
dependencies = dependencies.concat(pluginDeps);
}
this.dependencies.setDependencies(relativePath, dependencies);
}

if (this.requiresModuleApiPolyfill) {
return `export default Ember.HTMLBars.template(${precompiled});`;
} else {
return `import { createTemplateFactory } from '@ember/template-factory';\n\nexport default createTemplateFactory(${precompiled});`;
}
} catch (error) {
rethrowBuildError(error);
return [
`import { hbs } from 'ember-cli-htmlbars';`,
`export default hbs('${jsStringEscape(string)}', { moduleName: '${jsStringEscape(
relativePath
)}' });`,
'',
].join('\n');
}

getDestFilePath(relativePath) {
if (relativePath.endsWith('.hbs')) {
return relativePath.replace(/\.hbs$/, '.js');
}
}

_buildOptionsForHash() {
let strippedOptions = {};

for (let key in this.options) {
if (key !== 'templateCompiler') {
strippedOptions[key] = this.options[key];
}
}

strippedOptions._requiresModuleApiPolyfill = this.requiresModuleApiPolyfill;

return strippedOptions;
}

optionsHash() {
if (!this._optionsHash) {
let templateCompilerCacheKey = utils.getTemplateCompilerCacheKey(
this.options.templateCompilerPath
);

this._optionsHash = crypto
.createHash('md5')
.update(stringify(this._buildOptionsForHash()), 'utf8')
.update(templateCompilerCacheKey, 'utf8')
.digest('hex');
}

return this._optionsHash;
}

cacheKeyProcessString(string, relativePath) {
return (
this.optionsHash() + Filter.prototype.cacheKeyProcessString.call(this, string, relativePath)
);
}
}

TemplateCompiler.prototype.extensions = ['hbs', 'handlebars'];
TemplateCompiler.prototype.targetExtension = 'js';

function pluginsWithDependencies(registeredPlugins) {
let found = [];
for (let i = 0; i < registeredPlugins.length; i++) {
if (registeredPlugins[i].getDependencies) {
found.push(registeredPlugins[i]);
}
}
return found;
}

module.exports = TemplateCompiler;
32 changes: 0 additions & 32 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,34 +190,6 @@ function getTemplateCompiler(templateCompilerPath, EmberENV = {}) {
return context.module.exports;
}

function initializeEmberENV(templateCompiler, EmberENV) {
if (!templateCompiler || !EmberENV) {
return;
}

let props;

if (EmberENV.FEATURES) {
props = Object.keys(EmberENV.FEATURES);

props.forEach((prop) => {
templateCompiler._Ember.FEATURES[prop] = EmberENV.FEATURES[prop];
});
}

if (EmberENV) {
props = Object.keys(EmberENV);

props.forEach((prop) => {
if (prop === 'FEATURES') {
return;
}

templateCompiler._Ember.ENV[prop] = EmberENV[prop];
});
}
}

function setup(pluginInfo, options) {
let projectConfig = options.projectConfig || {};
let templateCompilerPath = options.templateCompilerPath;
Expand Down Expand Up @@ -374,13 +346,9 @@ function setupPlugins(wrappers) {

module.exports = {
buildOptions,
initializeEmberENV,
setup,
makeCacheKey,
setupPlugins,
isColocatedBabelPluginRegistered,
isInlinePrecompileBabelPluginRegistered,
buildParalleizedBabelPlugin,
getTemplateCompiler,
getTemplateCompilerCacheKey,
};
7 changes: 5 additions & 2 deletions node-tests/addon-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,11 @@ describe('ember-cli-htmlbars addon', function () {
yield output.build();

expect(output.read()).to.deep.equal({
'hello.js':
'export default Ember.HTMLBars.template({"id":"pb4oG9l/","block":"[[[10,0],[12],[1,\\"Hello, World!\\"],[13]],[],false,[]]","moduleName":"hello.hbs","isStrictMode":false});',
'hello.js': [
`import { hbs } from 'ember-cli-htmlbars';`,
`export default hbs('<div>Hello, World!</div>', { moduleName: 'hello.hbs' });`,
'',
].join('\n'),
});
})
);
Expand Down
Loading

0 comments on commit 2f2cac9

Please sign in to comment.