glimmer-babel preset failing for typescript files
lifeart opened this issue · 10 comments
given:
import Component, { hbs } from '@glimmerx/component';
import HelloWorld from './components/HelloWorld.hbs';
export default class App extends Component {
static template = hbs`
<HelloWorld />
`
}
error:
once I'm console.log(HelloWorld)
, everything works just fine, looks like plugin should count .hbs
, .gbs
extensions
given:
import Component, { hbs } from '@glimmerx/component';
import HelloWorld from './components/HelloWorld.hbs';
console.log(HelloWorld);
export default class App extends Component {
static template = hbs`
<HelloWorld />
`
}
may be an issue in https://github.com/ember-cli/babel-plugin-htmlbars-inline-precompile
looks like plugin does not handle case with template as static property and external component import
workaround before transform to get it working
const imports = parseStaticImports(code).filter(e => {
return e.moduleName.startsWith('@glimmerx/modifier') || !e.moduleName.startsWith("@");
}).map((el) => [...el.namedImports.map(e => e.alias), el.defaultImport]).reduce((acc, items) => {
return acc.concat(items);
}, []);
code = `
${code};
//
[${imports.map(e => `${e}`).join(',')}];
`;
problem in this function: https://github.com/ember-cli/babel-plugin-htmlbars-inline-precompile/blob/master/index.js#L142
because imported template is not binded to the scope
// this implementation of getScope solves missing scope lookup
function getScope(scope) {
let names = Object.keys(scope.references);
while (scope) {
for (let binding in scope.bindings) {
names.push(binding);
}
if (!scope.parent) {
Object.keys(scope.references).forEach((ref) => {
if (!names.includes(ref)) {
names.push(ref);
}
});
}
scope = scope.parent;
}
return names;
}
but not solve final problem
diff --git a/node_modules/babel-plugin-htmlbars-inline-precompile/index.js b/node_modules/babel-plugin-htmlbars-inline-precompile/index.js
index 700b3d6..29d9316 100644
--- a/node_modules/babel-plugin-htmlbars-inline-precompile/index.js
+++ b/node_modules/babel-plugin-htmlbars-inline-precompile/index.js
@@ -143,6 +143,14 @@ module.exports = function (babel) {
names.push(binding);
}
+ if (!scope.parent) {
+ Object.keys(scope.references).forEach((ref) => {
+ if (!names.includes(ref)) {
+ names.push(ref);
+ }
+ });
+ }
+
scope = scope.parent;
}
next issue we have:
on
modifier import is removed after compilation, but scope
referencing to it
input:
import Component, { hbs } from '@glimmerx/component';
import { on, action } from '@glimmerx/modifier';
export default class App extends Component {
updateValue() { console.log(1) }
static template = hbs`
<input {{on 'input' this.updateValue}} />
`;
}
compiled output:
import { setComponentTemplate as _setComponentTemplate } from "@glimmer/core";
import { createTemplateFactory as _createTemplateFactory } from "@glimmer/core";
import Component from '@glimmerx/component';
export default class App extends Component {
updateValue() {
console.log(1);
}
}
_setComponentTemplate(_createTemplateFactory(
/*
<input {{on 'input' this.updateValue}} />
*/
{
"id": "HHfcxqIY",
"block": "[[[1,\"\\n \"],[11,\"input\"],[4,[32,0],[\"input\",[30,0,[\"updateValue\"]]],null],[12],[13],[1,\"\\n \"]],[],false,[]]",
"moduleName": "(unknown template module)",
"scope": () => [on],
"isStrictMode": true
}), App);
if I import { action, on }
from @glimmerx/modifier
;
I have only { action }
after template compilation:
If I replace @glimmerx
with @glimmer
:
looks like issue in @babel/preset-typescript
, it's removing unused imports, may be related issue: babel/babel#9723
// https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAMwhRUIjgciRTBuAKAIFMAPSWOAE2IQEMBXAG3gGMm6BnTuAMWQBGdKHADeAXyA
possible workaround: not use ts, or parse TS -> apply hbs transform -> print ts,
I believe that the TS removing the imports also prevents template imports to work in ember with TS. So, fixing support for TS would be the best approach instead of not having TS support at all.
@josemarluedke I have one workaround for vite, collecting all imports before ast transform and appending all imports to array, to prevent ts deleting it.
import { transformSync } from "@babel/core";
import babelGlimmerPreset from "@glimmerx/babel-preset";
import tsPreset from "@babel/preset-typescript";
import parseStaticImports from "parse-static-imports";
const templateFileRegex = /\.(hbs)$/;
const fixDelimiter = '// [will-be-removed]';
export default function vitePluginBabelImport(
plgOptions
) {
let viteConfig;
return {
name: 'vite:glimmerx',
enforce: 'pre',
configResolved(resolvedConfig) {
viteConfig = resolvedConfig;
},
transform(rawCode, id) {
let code = rawCode;
if (templateFileRegex.test(id)) {
code = `
import { hbs } from '@glimmerx/component';
export default hbs\`${rawCode.trim()}\`;
`.trim();
} else if (!id.endsWith('.ts') && !id.endsWith('.js')) {
return;
}
const imports = parseStaticImports(code).filter(e => {
return e.moduleName.startsWith('@glimmerx/') || !e.moduleName.startsWith("@");
}).map((el) => [...el.namedImports.map(e => e.alias), el.defaultImport]).reduce((acc, items) => {
return acc.concat(items);
}, []);
code = `
${code};
${fixDelimiter}
[${imports.map(e => `${e}`).join(',')}];
`;
const result = transformSrcCode(code, id, plgOptions, viteConfig);
return {
code: result.split(fixDelimiter)[0].trim(),
map: null,
};
},
};
}
function transformSrcCode(code, fileName, plgOptions, viteConfig) {
let result = transformSync(code, {
sourceType: "module",
babelrc: false,
configFile: false,
envName: viteConfig.mode,
filename: fileName,
presets: [tsPreset, function(api, opts) {
return babelGlimmerPreset(api, {...opts, ...{
isDebug: !viteConfig.isProduction
}})
}]
});
return result.code;
}
What needs resolving to make this preset work for TS?
@knownasilya with latest TS compiler, new flag introduced, to not delete "not used" imports. It should help (but i'm did not tryied)