Skip to content

Commit

Permalink
Merge pull request #2120 from patricklx/fix-gts-in-v1-addons
Browse files Browse the repository at this point in the history
fix gts in v1 addons
  • Loading branch information
ef4 authored Oct 1, 2024
2 parents 4d777e7 + d8ee8db commit 2d0d93e
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 2 deletions.
31 changes: 30 additions & 1 deletion packages/compat/src/v1-addon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,10 @@ export default class V1Addon {
@Memoize()
private get templateCompilerBabelPlugin(): PluginItem | undefined {
let plugins = loadAstPlugins(this.addonInstance.registry);
let hasTemplateTag = this.addonInstance.addons.find((a: any) => a.name === 'ember-template-imports');
// our macros don't run here in stage1
plugins = plugins.filter((p: any) => !isEmbroiderMacrosPlugin(p));
if (plugins.length > 0) {
if (plugins.length > 0 || hasTemplateTag) {
let compilerPath = require.resolve('ember-source/dist/ember-template-compiler.js', {
paths: [findTopmostAddon(this.addonInstance).parent.root],
});
Expand Down Expand Up @@ -205,6 +206,34 @@ export default class V1Addon {
// the older inline template compiler is present
return true;
}
if (this.addonInstance.addons.find((a: any) => a.name === 'ember-template-imports')) {
/**
* Stage1 will always run custom broccoli preprocessors. So that's enough to convert:
*
* import Thing from './thing';
* <template><Thing/></template>
* to
*
* import Thing from './thing';
* import { template } from '@ember/template-compiler';
* export default template("Thing", {
* eval: function() { return eval(arguments[0]) } })
* });
* This is really all we need to do at stage1, since this is now valid Javascript that could appear in a v2 addon.
*
* But if the addon is also using TS, we also need to run the typescript transform before it will be valid JS. And if the typescript transform was being truly correct it would not try to delete the import because the eval can see the imported binding. That's why we have an eval. It's a standards-compliant want of gaining access to everything in scope.
*
* Normally we only use babel-plugin-ember-template-compilation in stage1 to run custom AST transforms. Since there are none in the addon, we don't add it. The fix here is helping because there is a new reason to add it. It will further convert the above example to:
*
* import Thing from './thing';
* import { template } from '@ember/template-compiler';
* export default template("Thing", {
* scope: () => ({ Thing })
* });
* which typescript then respects.
*/
return true;
}

if (
this.addonInstance.addons.find(
Expand Down
15 changes: 14 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

80 changes: 80 additions & 0 deletions tests/scenarios/compat-stage2-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,86 @@ stage2Scenarios
});
});

stage2Scenarios
.map('gts-files-in-addons-are-pre-processed-with-template-compilation', app => {
let depA = addAddon(app, 'dep-a');
depA.linkDependency('ember-template-imports', { baseDir: __dirname });
depA.linkDependency('ember-cli-babel', { baseDir: __dirname, resolveName: 'ember-cli-babel-latest' });

merge(depA.files, {
'index.js': `
'use strict';
module.exports = {
name: require('./package').name,
options: {
'ember-cli-babel': { enableTypeScriptTransform: true },
},
};`,
addon: {
components: {
'other.gts': `
import Component from '@glimmer/component';
export default class extends Component {
abc: string;
<template>
other
</template>
};
`,
'gts-component.gts': `
import Component from '@glimmer/component';
import OtherComponent from './other';
export default class extends Component {
abc: string;
<template>
this is gts
with <OtherComponent />
</template>
};
`,
},
},
app: {
components: {
'gts-component.js': 'export { default } from "dep-a/components/gts-component"',
},
},
});
})
.forEachScenario(scenario => {
Qmodule(scenario.name, function (hooks) {
throwOnWarnings(hooks);

let app: PreparedApp;

hooks.before(async assert => {
app = await scenario.prepare();
let result = await app.execute('ember build', { env: { STAGE2_ONLY: 'true' } });
assert.equal(result.exitCode, 0, result.output);
});

let expectAudit = setupAuditTest(hooks, () => ({ app: app.dir, 'reuse-build': true }));

test('no audit issues', function () {
expectAudit.hasNoFindings();
});

test('gts is processed with template-compilation', function () {
let expectModule = expectAudit.module('./assets/my-app.js');
// this is to make sure that the babel plugin template compilation runs and thus
// make imports that are only used in templates bound and not removed by typescript
expectModule
.resolves('my-app/components/gts-component.js')
.toModule()
.resolves('dep-a/components/gts-component')
.toModule()
.codeContains(`import OtherComponent from './other';`);
});
});
});

stage2Scenarios
.map('static-with-rules', app => {
app.addDependency('some-library', '1.0.0');
Expand Down
1 change: 1 addition & 0 deletions tests/scenarios/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
"ember-source-canary": "https://s3.amazonaws.com/builds.emberjs.com/canary/shas/756f0e3f98b8ca5edf443fe57318b4dac692bffa.tgz",
"ember-source-latest": "npm:ember-source@latest",
"ember-truth-helpers": "^3.0.0",
"ember-template-imports": "^4.1.2",
"execa": "^5.1.1",
"popper.js": "^1.16.1",
"tslib": "^2.6.0",
Expand Down

0 comments on commit 2d0d93e

Please sign in to comment.