Migrating to glint v2
Glint released a Volar-based v2 at the end of September. It's time to update, now that we have migrated to <template> tag. (It's okay if some hbs code remain. They just won't be type-checked.)
Currently, the official upgrade guide is minimal and assumes that you are familiar with the changes made in the Ember ecosystem. This post aims to fill in gaps and provide a guide that everyone can use.
1. Starting point
I'll assume the following about your dependencies to cover the 80% case.
- Glint is on
1.5.2, i.e. the "core four" (@glint/core,@glint/environment-ember-loose,@glint/environment-ember-template-imports, and@glint/template) run on this version. - Your
tsconfig.jsonextends@tsconfig/emberin apps and addons. - You consume native types from Ember, i.e.
ember-sourceis on5.1.0or higher.
These conditions imply that your tsconfig.json can be as simple as the following for Ember apps:
{
"extends": "@tsconfig/ember/tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"my-app/tests/*": ["tests/*"],
"my-app/*": ["app/*"],
"*": ["types/*"]
},
"types": ["ember-source/types"]
},
"glint": {
"environment": ["ember-loose", "ember-template-imports"]
},
"include": ["app/**/*", "tests/**/*", "types/**/*"]
}Not to worry, I'll describe alternatives if conditions 2 and 3 aren't met.
2. How to migrate apps
The following steps apply to both v1 (classic, Webpack) and v2 (Vite) apps. You can run lint:types to check your progress.
a. Update package.json
Replace the core four with @glint/ember-tsc and @glint/template. Optionally, add @glint/tsserver-plugin to support all IDEs (not just VS Code).
{
"name": "my-app",
"scripts: {
"lint:types": "glint"
},
"devDependencies": {
- "@glint/core": "^1.5.2",
- "@glint/environment-ember-loose": "^1.5.2",
- "@glint/environment-ember-template-imports": "^1.5.2",
- "@glint/template": "^1.5.2",
+ "@glint/ember-tsc": "^1.0.8",
+ "@glint/template": "^1.7.3",
+ "@glint/tsserver-plugin": "^2.0.8",
"@tsconfig/ember": "^3.0.12",
"typescript": "^5.9.3"
}
}Then, replace the glint command with ember-tsc.
{
"name": "my-app",
"scripts: {
- "lint:types": "glint"
+ "lint:types": "ember-tsc --noEmit"
},
"devDependencies": {
"@glint/ember-tsc": "^1.0.8",
"@glint/template": "^1.7.3",
"@glint/tsserver-plugin": "^2.0.8",
"@tsconfig/ember": "^3.0.12",
"typescript": "^5.9.3"
}
}Finally, use your package manager to install the dependencies.
b. Update tsconfig.json
The simplest configuration from above becomes,
{
"extends": "@tsconfig/ember/tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"my-app/tests/*": ["tests/*"],
"my-app/*": ["app/*"],
"*": ["types/*"]
},
"plugins": [
{
"name": "@glint/tsserver-plugin"
}
],
"types": ["ember-source/types", "@glint/ember-tsc/types"]
},
"include": ["app/**/*", "tests/**/*", "types/**/*"]
}That is, remove the glint field, since @glint/environment-ember-loose and @glint/environment-ember-template-imports no longer exist. Then, update compilerOptions.{plugins,types} to account for @glint/tsserver-plugin and the ambient types from @glint/ember-tsc.
i. Use @ember/app-tsconfig?
Only the extends field should differ.
{
"extends": "@ember/app-tsconfig"
}ii. Use DefinitelyTyped packages?
These packages (e.g. @types/ember__component), whose types are compatible with ember-source@3.28 and 4.x, can continue to be used. That is, you can update glint to v2 if ember-source is at least 3.27 (the minimum version that ember-template-imports supports).
The types field excludes ember-source, since it doesn't provide types yet.
{
"types": ["@glint/ember-tsc/types"]
}iii. Use additionalGlobals or additionalSpecialForms?
If you used additionalGlobals (unlikely) or additionalSpecialForms (possible for ember-truth-helpers), re-introduce it in the glint field as a top-level key.
Here's how to configure ember-truth-helpers so that its helpers—whether named- or default-imported—can perform truthiness narrowing.
{
"extends": "@tsconfig/ember/tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"my-app/tests/*": ["tests/*"],
"my-app/*": ["app/*"],
"*": ["types/*"]
},
"plugins": [
{
"name": "@glint/tsserver-plugin"
}
],
"types": ["ember-source/types", "@glint/ember-tsc/types"]
},
"include": ["app/**/*", "tests/**/*", "types/**/*"],
"glint": {
"additionalSpecialForms": {
"imports": {
"ember-truth-helpers": {
"and": "&&",
"eq": "===",
"not": "!",
"not-eq": "!==",
"or": "||"
},
"ember-truth-helpers/helpers/and": {
"default": "&&"
},
"ember-truth-helpers/helpers/eq": {
"default": "==="
},
"ember-truth-helpers/helpers/not": {
"default": "!"
},
"ember-truth-helpers/helpers/not-eq": {
"default": "!=="
},
"ember-truth-helpers/helpers/or": {
"default": "||"
}
}
}
}
}c. Remove references to glint v1
Since @glint/environment-ember-loose and @glint/environment-ember-template-imports are gone, you can remove these dead code:
declare moduleblocks (look fordeclare module '@glint/environment-ember-loose/registry') in the app's components, helpers, modifiers, andtypes/global.d.ts(or a similar file).TestContextpassed torender()in rendering tests.- Imports of
@glint/environment-ember-looseand@glint/environment-ember-template-imports, as well as of all template registries, intypes/global.d.ts.
3. How to migrate v1 addons
ember-cli began to create v1 addons with typescript differently in 5.2.0, so there are two scenarios to consider.
As a rule of thumb, your addon came from the old blueprint if it depends on ember-cli-typescript (the prepack script shows ember ts:precompile). If from the new one, the addon will have 2 configuration files for TypeScript, and the prepack script will show tsc --project tsconfig.declarations.json.
For brevity, this guide only considers v1 addons generated from the old blueprint and won't mention @glint/tsserver-plugin again. If you had created a v1 addon from the newer blueprint, the idea remains the same: Update tsconfig.json and the scripts in package.json so that your addon is linted and built the same.
{
"name": "my-v1-addon",
"scripts": {
- "lint:types": "glint",
+ "lint:types": "ember-tsc --noEmit",
"prepack": "ember ts:precompile",
"postpack": "ember ts:clean"
},
"dependencies": {
"ember-cli-typescript": "^5.3.0",
"ember-template-imports": "^4.3.0"
},
"devDependencies": {
- "@glint/core": "^1.5.2",
- "@glint/environment-ember-loose": "^1.5.2",
- "@glint/environment-ember-template-imports": "^1.5.2",
- "@glint/template": "^1.5.2",
+ "@glint/ember-tsc": "^1.0.8",
+ "@glint/template": "^1.7.3",
"@tsconfig/ember": "^3.0.12",
"typescript": "^5.9.3"
}
}{
"extends": "@tsconfig/ember/tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"dummy/tests/*": ["tests/*"],
"dummy/*": ["tests/dummy/app/*", "app/*"],
"my-addon": ["addon"],
"my-addon/*": ["addon/*"],
"my-addon/test-support": ["addon-test-support"],
"my-addon/test-support/*": ["addon-test-support/*"],
"*": ["types/*"]
},
+ "types": ["ember-source/types", "@glint/ember-tsc/types"]
},
- "glint": {
- "environment": ["ember-loose", "ember-template-imports"]
- },
"include": ["addon/**/*", "addon-test-support/**/*", "tests/**/*", "types/**/*"]
}Finally, remove any references to @glint/environment-ember-loose. The declare module blocks and template registry can be removed if you decide to not support consuming apps and addons with loose-mode templates.
4. How to migrate v2 addons
First, replace the dependencies for glint and update the lint:types script.
{
"name": "my-v2-addon",
"scripts": {
"build": "rollup --config"
- "lint:types": "glint",
+ "lint:types": "ember-tsc --noEmit"
},
"devDependencies": {
- "@glint/core": "^1.5.2",
- "@glint/environment-ember-loose": "^1.5.2",
- "@glint/environment-ember-template-imports": "^1.5.2",
- "@glint/template": "^1.5.2",
+ "@glint/ember-tsc": "^1.0.8",
+ "@glint/template": "^1.7.3",
"@tsconfig/ember": "^3.0.12",
"typescript": "^5.9.3"
}
}Next, we ensure that the package is linted and built the same.
import { Addon } from '@embroider/addon-dev/rollup';
import { babel } from '@rollup/plugin-babel';
const addon = new Addon({
srcDir: 'src',
destDir: 'dist',
});
export default {
output: addon.output(),
plugins: [
addon.publicEntrypoints(['**/*.js', 'index.ts', 'template-registry.ts']),
addon.appReexports([
'components/**/*.js',
'helpers/**/*.js',
'modifiers/**/*.js',
'services/**/*.js',
]),
addon.dependencies(),
babel({
babelHelpers: 'bundled',
configFile: './babel.config.mjs',
extensions: ['.gjs', '.gts', '.js', '.ts'],
}),
addon.hbs(),
addon.gjs(),
// Emit .d.ts declaration files
- addon.declarations('declarations'),
+ addon.declarations(
+ 'declarations',
+ `pnpm ember-tsc --declaration --project tsconfig.json`,
+ ),
addon.keepAssets(['**/*.css']),
addon.clean(),
],
};{
"extends": "@tsconfig/ember/tsconfig.json",
"compilerOptions": {
"allowImportingTsExtensions": true,
+ "declaration": true,
"declarationDir": "declarations",
+ "declarationMap": true,
+ "emitDeclarationOnly": true,
+ "noEmit": false,
"rootDir": "./src",
- "types": ["ember-source/types"]
+ "types": ["ember-source/types", "@glint/ember-tsc/types"]
},
- "glint": {
- "environment": ["ember-loose", "ember-template-imports"]
- },
"include": ["src/**/*", "unpublished-development-types/**/*"]
}Finally, remove references to @glint/environment-ember-loose. In particular, the file unpublished-development-types/index.d.ts can be cleared or removed. The template registry can be removed if you decide to not support consuming apps and addons with loose-mode templates.