Skip to content

Commit

Permalink
Reform internal use of template compiler
Browse files Browse the repository at this point in the history
Previously, ember-source had a weird custom way of compiling templates
that appear within its own source. This PR makes it work the same way we
do everywhere else, using babele-plugin-ember-template-compilation.

This required solving a boostrapping problem: the babel plugin needs
ember-template-compiler.js, our build produces
ember-template-compiler.js, but our build wants to use the babel plugin.
I solved it by making the template compiler directly evaluatable in
node, with no build at all.

The *full* legacy ember-template-compiler API has a lot of silly things
shoved into it (like a reexport of all of the `Ember` metapackage), and
that was inextricably circular, so I introduced
`ember-template-compiler/minimal` for this internal use case.
  • Loading branch information
ef4 committed Dec 1, 2023
1 parent f679f03 commit c3afc77
Show file tree
Hide file tree
Showing 29 changed files with 1,930 additions and 451 deletions.
39 changes: 2 additions & 37 deletions broccoli/glimmer-template-compiler.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,4 @@
'use strict';

const Filter = require('broccoli-persistent-filter');
const { stripIndent } = require('common-tags');

GlimmerTemplatePrecompiler.prototype = Object.create(Filter.prototype);

function GlimmerTemplatePrecompiler(inputTree, options) {
if (!(this instanceof GlimmerTemplatePrecompiler)) {
return new GlimmerTemplatePrecompiler(inputTree, options);
}

Filter.call(this, inputTree, {});

this.inputTree = inputTree;
if (!options.glimmer) {
throw new Error('No glimmer option provided!');
}
this.precompile = options.glimmer.precompile;
}

GlimmerTemplatePrecompiler.prototype.extensions = ['hbs'];
GlimmerTemplatePrecompiler.prototype.targetExtension = 'js';

GlimmerTemplatePrecompiler.prototype.baseDir = function () {
return __dirname;
};

GlimmerTemplatePrecompiler.prototype.processString = function (content, relativePath) {
let compiled = this.precompile(content, {
meta: { moduleName: relativePath },
});
return stripIndent`
import { templateFactory } from '@glimmer/opcode-compiler';
export default templateFactory(${compiled});
`;
};

module.exports = GlimmerTemplatePrecompiler;
require('@swc-node/register');
module.exports = require('../packages/ember-template-compiler/minimal.ts');
18 changes: 3 additions & 15 deletions broccoli/packages.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ const { VERSION } = require('./version');
const PackageJSONWriter = require('./package-json-writer');
const WriteFile = require('broccoli-file-creator');
const StringReplace = require('broccoli-string-replace');
const GlimmerTemplatePrecompiler = require('./glimmer-template-compiler');
const VERSION_PLACEHOLDER = /VERSION_STRING_PLACEHOLDER/g;
const canaryFeatures = require('./canary-features');

Expand Down Expand Up @@ -54,32 +53,21 @@ module.exports.qunit = function _qunit() {

module.exports.getPackagesES = function getPackagesES() {
let input = new Funnel(`packages`, {
exclude: ['loader/**', 'external-helpers/**'],
exclude: ['loader/**', 'external-helpers/**', '**/node_modules'],
destDir: `packages`,
});

let debuggedInput = debugTree(input, `get-packages-es:input`);

let compiledTemplatesAndTypescript = new GlimmerTemplatePrecompiler(debuggedInput, {
persist: true,
glimmer: require('@glimmer/compiler'),
annotation: `get-packages-es templates -> es`,
});

let debuggedCompiledTemplatesAndTypeScript = debugTree(
compiledTemplatesAndTypescript,
`get-packages-es:templates-output`
);

let nonTypeScriptContents = debugTree(
new Funnel(debuggedCompiledTemplatesAndTypeScript, {
new Funnel(debuggedInput, {
srcDir: 'packages',
exclude: ['**/*.ts'],
}),
'get-packages-es:js:output'
);

let typescriptContents = new Funnel(debuggedCompiledTemplatesAndTypeScript, {
let typescriptContents = new Funnel(debuggedInput, {
include: ['**/*.ts'],
});

Expand Down
21 changes: 13 additions & 8 deletions ember-cli-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,21 @@ module.exports = function ({ project }) {
let emberBundles = withTargets(project, emberSource.buildEmberBundles.bind(emberSource));

let packages = debugTree(
new MergeTrees([
// dynamically generated packages
emberVersionES(),
new MergeTrees(
[
// packages/** (after typescript compilation)
getPackagesES(),

// packages/** (after typescript compilation)
getPackagesES(),
emberVersionES(),

// externalized helpers
babelHelpers(),
]),
// externalized helpers
babelHelpers(),
],
{
// we're replacing the ember/verion file with the actual version number
overwrite: true,
}
),
'packages:initial'
);

Expand Down
12 changes: 12 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,17 @@ module.exports = {
let isEmberSource = this.project.name() === 'ember-source';
let babelHelperPlugin = injectBabelHelpers(isEmberSource);

let compilerPath;
if (isEmberSource) {
// Here we are using the template compiler by directly evaluating it in
// node, because we *are* the build that produces
// ember-template-compiler.js.
compilerPath = path.resolve(__dirname, '../broccoli/glimmer-template-compiler');
} else {
// When we're building an app, we use the already built template compiler.
compilerPath = path.resolve(__dirname, '../dist/ember-template-compiler.js');
}

let options = {
'ember-cli-babel': {
disableDebugTooling: true,
Expand All @@ -155,6 +166,7 @@ module.exports = {
plugins: [
babelHelperPlugin,
buildDebugMacroPlugin(!isProduction),
['babel-plugin-ember-template-compilation', { compilerPath }],
...vmBabelPlugins({ isDebug: !isProduction }),
],
}),
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@
"@embroider/shared-internals": "^2.5.0",
"@rollup/plugin-babel": "^6.0.3",
"@simple-dom/document": "^1.4.0",
"@swc/core": "^1.3.100",
"@swc-node/register": "^1.6.8",
"@tsconfig/ember": "^2.0.0",
"@types/node": "^18.11.11",
"@types/qunit": "^2.19.4",
Expand Down
3 changes: 0 additions & 3 deletions packages/@ember/-internals/glimmer/lib/templates/empty.d.ts

This file was deleted.

Empty file.
4 changes: 4 additions & 0 deletions packages/@ember/-internals/glimmer/lib/templates/empty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { precompileTemplate } from '@ember/template-compilation';
export default precompileTemplate('', {
moduleName: 'packages/@ember/-internals/glimmer/lib/templates/empty.hbs',
});
3 changes: 0 additions & 3 deletions packages/@ember/-internals/glimmer/lib/templates/input.d.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<input
import { precompileTemplate } from '@ember/template-compilation';
export default precompileTemplate(
`<input
{{!-- for compatibility --}}
id={{this.id}}
class={{this.class}}
Expand All @@ -14,4 +16,6 @@
{{on "keyup" this.keyUp}}
{{on "paste" this.valueDidChange}}
{{on "cut" this.valueDidChange}}
/>
/>`,
{ moduleName: 'packages/@ember/-internals/glimmer/lib/templates/input.hbs' }
);
3 changes: 0 additions & 3 deletions packages/@ember/-internals/glimmer/lib/templates/link-to.d.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<a
import { precompileTemplate } from '@ember/template-compilation';
export default precompileTemplate(
`<a
{{!-- for compatibility --}}
id={{this.id}}
class={{this.class}}
Expand All @@ -15,4 +17,6 @@
href={{this.href}}
{{on 'click' this.click}}
>{{yield}}</a>
>{{yield}}</a>`,
{ moduleName: 'packages/@ember/-internals/glimmer/lib/templates/link-to.hbs' }
);
3 changes: 0 additions & 3 deletions packages/@ember/-internals/glimmer/lib/templates/outlet.d.ts

This file was deleted.

This file was deleted.

4 changes: 4 additions & 0 deletions packages/@ember/-internals/glimmer/lib/templates/outlet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { precompileTemplate } from '@ember/template-compilation';
export default precompileTemplate(`{{component (-outlet)}}`, {
moduleName: 'packages/@ember/-internals/glimmer/lib/templates/outlet.hbs',
});
3 changes: 0 additions & 3 deletions packages/@ember/-internals/glimmer/lib/templates/root.d.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/@ember/-internals/glimmer/lib/templates/root.hbs

This file was deleted.

4 changes: 4 additions & 0 deletions packages/@ember/-internals/glimmer/lib/templates/root.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { precompileTemplate } from '@ember/template-compilation';
export default precompileTemplate(`{{component this}}`, {
moduleName: 'packages/@ember/-internals/glimmer/lib/templates/root.hbs',
});

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<textarea
import { precompileTemplate } from '@ember/template-compilation';
export default precompileTemplate(
`<textarea
{{!-- for compatibility --}}
id={{this.id}}
class={{this.class}}
Expand All @@ -12,4 +14,6 @@
{{on "keyup" this.keyUp}}
{{on "paste" this.valueDidChange}}
{{on "cut" this.valueDidChange}}
/>
/>`,
{ moduleName: 'packages/@ember/-internals/glimmer/lib/templates/textarea.hbs' }
);
5 changes: 4 additions & 1 deletion packages/@ember/debug/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import type { WarnFunc } from './lib/warn';
import _warn from './lib/warn';

export { registerHandler as registerWarnHandler } from './lib/warn';
export { registerHandler as registerDeprecationHandler, DeprecationOptions } from './lib/deprecate';
export {
registerHandler as registerDeprecationHandler,
type DeprecationOptions,
} from './lib/deprecate';
export { default as inspect } from './lib/inspect';
export { isTesting, setTesting } from './lib/testing';
export { default as captureRenderTree } from './lib/capture-render-tree';
Expand Down
12 changes: 12 additions & 0 deletions packages/ember-template-compiler/minimal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// The main entrypoint of ember-template-compiler is the fairly-crufty
// backward-compatible API. In contrast, this is the subset of that that's
// actually used by babel-plugin-ember-template-compilation.
//
// This module exists so that ember-source can build itself -- the
// ember-template-compiler.js bundle it an output of the build, but the build
// needs to compile templates. Unlike the full ./index.ts, this module can be
// directly evaluted in node because it doesn't try to pull in the whole kitchen
// sink.
export { default as precompile } from './lib/system/precompile';
export { buildCompileOptions as _buildCompileOptions } from './lib/system/compile-options';
export { preprocess as _preprocess, print as _print } from '@glimmer/syntax';
4 changes: 3 additions & 1 deletion packages/ember-template-compiler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"private": true,
"type": "module",
"exports": {
".": "./index.ts"
".": "./index.ts",
"./minimal": "./minimal.ts"
},
"dependencies": {
"@ember/-internals": "workspace:*",
Expand All @@ -21,6 +22,7 @@
"@ember/routing": "workspace:*",
"@ember/runloop": "workspace:*",
"@ember/service": "workspace:*",
"@ember/template-compilation": "workspace:*",
"@ember/utils": "workspace:*",
"@glimmer/compiler": "0.85.13",
"@glimmer/env": "^0.1.7",
Expand Down
2 changes: 0 additions & 2 deletions packages/ember/version.d.ts

This file was deleted.

2 changes: 2 additions & 0 deletions packages/ember/version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// this file gets replaced with the real value during the build
export default 'VERSION_GOES_HERE';
Loading

0 comments on commit c3afc77

Please sign in to comment.