Skip to content

Commit

Permalink
Add rollup declarations plugin
Browse files Browse the repository at this point in the history
This invokes glint as a rollup plugin, and contains a workaround for broken gts imports, see typed-ember/glint#628
  • Loading branch information
simonihmig committed Dec 9, 2024
1 parent 18d14eb commit 02ffe58
Show file tree
Hide file tree
Showing 7 changed files with 271 additions and 5 deletions.
6 changes: 6 additions & 0 deletions packages/addon-dev/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
testEnvironment: 'node',
testMatch: [
'<rootDir>/tests/**/*.test.js',
],
};
8 changes: 7 additions & 1 deletion packages/addon-dev/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,26 @@
"@embroider/core": "workspace:^",
"@rollup/pluginutils": "^4.1.1",
"content-tag": "^3.0.0",
"execa": "^5.1.1",
"fs-extra": "^10.0.0",
"minimatch": "^3.0.4",
"rollup-plugin-copy-assets": "^2.0.3",
"walk-sync": "^3.0.0",
"yargs": "^17.0.1"

},
"devDependencies": {
"@embroider/test-support": "workspace:*",
"@glimmer/syntax": "^0.84.2",
"@glint/core": "^1.5.0",
"@glint/template": "^1.5.0",
"@glint/environment-ember-loose": "^1.5.0",
"@glint/environment-ember-template-imports": "^1.5.0",
"@types/fs-extra": "^9.0.12",
"@types/minimatch": "^3.0.4",
"@types/yargs": "^17.0.3",
"rollup": "^3.23.0",
"tmp": "^0.1.0",
"scenario-tester": "^4.0.0",
"typescript": "^5.4.5"
},
"engines": {
Expand Down
50 changes: 50 additions & 0 deletions packages/addon-dev/src/rollup-declarations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import execa from 'execa';
import walkSync from 'walk-sync';
import { readFile, writeFile } from 'fs/promises';

export default function rollupDeclarationsPlugin(declarationsDir: string) {
let glintPromise: Promise<void>;

return {
name: 'glint-dts',
buildStart: () => {
const runGlint = async () => {
await execa('glint', ['--declaration'], {
stdio: 'inherit',
preferLocal: true,
});

await fixDeclarationsInMatchingFiles(declarationsDir);
};

// We just kick off glint here early in the rollup process, without making rollup wait for this to finish, by not returning the promise
// The output of this is not relevant to further stages of the rollup build, this is just happening in parallel to other rollup compilation
glintPromise = runGlint();
},

// Make rollup wait for glint to have finished before calling the build job done
writeBundle: () => glintPromise,
};
}

async function fixDeclarationsInMatchingFiles(dir: string) {
const dtsFiles = walkSync(dir, {
globs: ['**/*.d.ts'],
directories: false,
includeBasePath: true,
});

return Promise.all(
dtsFiles.map(async (file) => {
const content = await readFile(file, { encoding: 'utf8' });

await writeFile(file, fixDeclarations(content));
})
);
}

// Strip any .gts extension from imports in d.ts files, as these won't resolve. See https://github.com/typed-ember/glint/issues/628
// Once Glint v2 is available, this shouldn't be needed anymore.
function fixDeclarations(content: string) {
return content.replaceAll(/from\s+['"]([^'"]+)\.gts['"]/g, `from '$1'`);
}
5 changes: 5 additions & 0 deletions packages/addon-dev/src/rollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { default as gjs } from './rollup-gjs-plugin';
import { default as publicEntrypoints } from './rollup-public-entrypoints';
import { default as appReexports } from './rollup-app-reexports';
import { default as keepAssets } from './rollup-keep-assets';
import { default as declarations } from './rollup-declarations';
import { default as dependencies } from './rollup-addon-dependencies';
import {
default as publicAssets,
Expand Down Expand Up @@ -108,4 +109,8 @@ export class Addon {
publicAssets(path: string, opts?: PublicAssetsOptions) {
return publicAssets(path, opts);
}

declarations(path: string) {
return declarations(path);
}
}
109 changes: 109 additions & 0 deletions packages/addon-dev/tests/declarations.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
'use strict';

import rollupDeclarationsPlugin from '../src/rollup-declarations';
import { Project } from 'scenario-tester';
import { rollup } from 'rollup';
import { readFile } from 'fs-extra';
import { join } from 'path';

const projectBoilerplate = {
'tsconfig.json': JSON.stringify({
include: ['src/**/*'],
compilerOptions: {
declaration: true,
declarationDir: 'declarations',
emitDeclarationOnly: true,
rootDir: './src',
allowImportingTsExtensions: true,
},
glint: {
environment: ['ember-loose', 'ember-template-imports'],
},
}),
};

async function generateProject(src: {}): Promise<Project> {
const project = new Project('my-addon', {
files: {
...projectBoilerplate,
src,
},
});
project.linkDevDependency('typescript', { baseDir: __dirname });
project.linkDevDependency('@glint/core', { baseDir: __dirname });
project.linkDevDependency('@glint/template', { baseDir: __dirname });
project.linkDevDependency('@glint/environment-ember-loose', {
baseDir: __dirname,
});
project.linkDevDependency('@glint/environment-ember-template-imports', {
baseDir: __dirname,
});

await project.write();

return project;
}

async function runRollup(dir: string, rollupOptions = {}) {
const currentDir = process.cwd();
process.chdir(dir);

try {
const bundle = await rollup({
input: './src/index.ts',
plugins: [rollupDeclarationsPlugin('declarations')],
...rollupOptions,
});

await bundle.write({ format: 'esm', dir: 'dist' });
} finally {
process.chdir(currentDir);
}
}

describe('declarations', function () {
let project: Project | null;

afterEach(() => {
project?.dispose();
project = null;
});

test('it generates dts output', async function () {
project = await generateProject({
'index.ts': 'export default 123',
});

await runRollup(project.baseDir);

expect(
await readFile(join(project.baseDir, 'declarations/index.d.ts'), {
encoding: 'utf8',
})
).toContain('export default');
});

test('it has correct imports', async function () {
project = await generateProject({
'index.ts': `
import foo from './foo.gts';
import bar from './bar.ts';
export { foo, bar };
`,
'foo.gts': 'export default 123',
'bar.ts': 'export default 234',
});

await runRollup(project.baseDir);

const output = await readFile(
join(project.baseDir, 'declarations/index.d.ts'),
{
encoding: 'utf8',
}
);

expect(output).toContain(`import foo from './foo';`);
expect(output).toContain(`import bar from './bar.ts';`);
});
});
96 changes: 93 additions & 3 deletions pnpm-lock.yaml

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

2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"./tests/scenarios/**/*.ts"
],
"compilerOptions": {
"target": "es2019",
"target": "es2021",
"module": "commonjs",
"declaration": true,
"typeRoots": ["types", "node_modules/@types"],
Expand Down

0 comments on commit 02ffe58

Please sign in to comment.