From e3a85e1f4778f681663d04e39c0b92b9eb225bce Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Tue, 1 Jul 2025 12:06:19 -0400 Subject: [PATCH 01/12] Add `--minimal` and `--no-compat` --- README.md | 43 +++++++++++ index.js | 161 ++++++++++++++++++++++++++++++++++++++++- tests/minimal.test.mjs | 156 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 358 insertions(+), 2 deletions(-) create mode 100644 tests/minimal.test.mjs diff --git a/README.md b/README.md index cf8f804a..1fe9d061 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,46 @@ If you have an existing app that you would like to upgrade to use Vite consider ``` pnpm dlx ember-cli@latest new my-app-name -b @ember/app-blueprint --pnpm ``` + +## Options + +### `--no-compat` + +``` +pnpm dlx ember-cli@latest new my-app-name \ + --blueprint @ember/app-blueprint@alpha \ + --pnpm \ + --no-compat +``` + +Does the following: +- enables `type=module` in package.json (required for vite-ssr, and many ESM tools) +- makes the build and boot _MUCH FASTER_ + (in large apps, this can have your app's boot be up to 1 minute faster) +- removes `@embroider/compat` + - removes support for: + - hbs (both for component files, and testing) + - content-for (in the HTML files) + - v1 addons + - node-land config/environment.js +- removes `ember-cli` + - ember-cli brings in a ton of old dependencies, so removing it makes installs much faster + - downside though is that you no longer have scaffolding (`ember g`) -- however, you could use `pnpm dlx ember-cli g ...` (or `npx ember-cli g`) + +### `--minimal` + +``` +pnpm dlx ember-cli@latest new my-app-name \ + --blueprint @ember/app-blueprint@alpha \ + --pnpm \ + --minimal +``` + +Does the following +- everything listed under `--no-compat` +- Removes all linting, formatting, and testing support + - leaves you with a minimal app that you can use for demos, and PRing to other repositories that have multi-framework support (and probably use other testing tools for that multi-framework support) +- different defaults: + - warp-drive becomes _opt-in_ (pass `--warp-drive` if you want it -- normally requires `--no-warp-drive` to remove) + - ember-welcome-page becomes _opt-in_ (normally requires `--no-welcome` to remove) + diff --git a/index.js b/index.js index 8da9e21a..489ab07b 100644 --- a/index.js +++ b/index.js @@ -80,6 +80,8 @@ module.exports = { options.packageManager === 'pnpm' && '"--pnpm"', options.ciProvider && `"--ci-provider=${options.ciProvider}"`, options.typescript && `"--typescript"`, + options.minimal && `"--minimal"`, + options.noCompat && `"--no-compat"`, !options.emberData && `"--no-ember-data"`, !options.warpDrive && `"--no-warp-drive"`, ] @@ -101,6 +103,37 @@ module.exports = { execBinPrefix = 'pnpm'; } + let welcome = options.welcome; + let warpDrive = options.warpDrive ?? options.emberData; + let minimal = false; + let compat = true; + /** + * --minimal overrides compat/no-compat + */ + if (options.minimal) { + minimal = true; + compat = false; + + // Invert defaults + { + welcome = options.welcome = process.argv.includes('--welcome'); + warpDrive = + options.emberData = + options.warpDrive = + process.argv.includes('--ember-data') || + process.argv.includes('--warp-drive'); + } + } + + if (!minimal) { + if (options.noCompat) { + compat = false; + } + } + + let noCompat = !compat; + let notMinimal = !minimal; + return { appDirectory: directoryForPackageName(name), name, @@ -113,14 +146,18 @@ module.exports = { options.packageManager !== 'yarn' && options.packageManager !== 'pnpm', invokeScriptPrefix, execBinPrefix, - welcome: options.welcome, + welcome, blueprint: 'app', blueprintOptions, lang: options.lang, - warpDrive: options.warpDrive ?? options.emberData, + warpDrive: warpDrive, ciProvider: options.ciProvider, typescript: options.typescript, packageManager: options.packageManager ?? 'npm', + compat, + noCompat, + minimal, + notMinimal, }; }, @@ -131,6 +168,10 @@ module.exports = { let files = this._super(); + // Locals is where we calculate defaults and such. + // Let's not duplicate that work here + options = this.locals(options); + if (options.ciProvider !== 'github') { files = files.filter((file) => file.indexOf('.github') < 0); } @@ -150,6 +191,43 @@ module.exports = { files = files.filter((file) => !file.includes('services/.gitkeep')); } + if (options.noCompat) { + files = files.filter((file) => { + return ( + !file.includes('deprecation-workflow') && + !file.includes('ember-cli') && + !file.includes('ember-cli-build.js') && + !file.includes('controllers/') && + !file.includes('config/environment.js') && + !file.includes('config/optional-features') && + !file.includes('config/targets') && + !file.includes('helpers/') + ); + }); + } + + if (options.minimal) { + files = files.filter((file) => { + return ( + !file.includes('.github/') && + !file.includes('.prettierignore') && + !file.includes('README') && + !file.includes('components/') && + !file.includes('eslint.config') && + !file.includes('prettierrc') && + !file.includes('public/') && + !file.includes('routes/') && + !file.includes('services/') && + !file.includes('stylelint') && + !file.includes('styles/') && + !file.includes('template-lintrc') && + !file.includes('testem') && + !file.includes('tests/') && + !file.includes('watchman') + ); + }); + } + this._files = files; return this._files; @@ -182,6 +260,85 @@ module.exports = { updatePackageJson(options, content) { let contents = JSON.parse(content); + if (options.minimal) { + // Remove linting + { + delete contents.scripts['format']; + delete contents.scripts['lint']; + delete contents.scripts['lint:format']; + delete contents.scripts['lint:fix']; + delete contents.scripts['lint:js']; + delete contents.scripts['lint:js:fix']; + delete contents.scripts['lint:css']; + delete contents.scripts['lint:css:fix']; + delete contents.scripts['lint:hbs']; + delete contents.scripts['lint:hbs:fix']; + + delete contents.devDependencies['@babel/eslint-parser']; + delete contents.devDependencies['@eslint/js']; + delete contents.devDependencies['concurrently']; + delete contents.devDependencies['ember-template-lint']; + delete contents.devDependencies['eslint']; + delete contents.devDependencies['eslint-config-prettier']; + delete contents.devDependencies['eslint-plugin-ember']; + delete contents.devDependencies['eslint-plugin-n']; + delete contents.devDependencies['eslint-plugin-qunit']; + delete contents.devDependencies['eslint-plugin-warp-drive']; + delete contents.devDependencies['globals']; + delete contents.devDependencies['prettier']; + delete contents.devDependencies['prettier-plugin-ember-template-tag']; + delete contents.devDependencies['stylelint']; + delete contents.devDependencies['stylelint-config-standard']; + delete contents.devDependencies['typescript-eslint']; + } + // Remove testing + { + delete contents.scripts['test']; + delete contents.devDependencies['@ember/test-helpers']; + delete contents.devDependencies['@ember/test-waiters']; + delete contents.devDependencies['ember-qunit']; + delete contents.devDependencies['qunit']; + delete contents.devDependencies['qunit-dom']; + delete contents.devDependencies['testem']; + } + // Extraneous / non-core deps. + // if folks go minimal, they know what they are doing + { + delete contents.devDependencies['ember-welcome-page']; + delete contents.devDependencies['tracked-built-ins']; + delete contents.devDependencies['ember-page-title']; + delete contents.devDependencies['ember-modifier']; + } + // common-in-the-vite-ecosystem alias + { + contents.scripts.dev = contents.scripts.start; + } + } + if (options.noCompat) { + contents.type = 'module'; + contents.engines.node = '>= 24'; + delete contents.directories; + delete contents.devDependencies['@ember/string']; + delete contents.devDependencies['@ember/optional-features']; + delete contents.devDependencies['@embroider/compat']; + delete contents.devDependencies['@embroider/config-meta-loader']; + delete contents.devDependencies['ember-resolver']; + // Users should use npx ember-cli instead + delete contents.devDependencies['ember-cli']; + delete contents.devDependencies['ember-cli-babel']; + delete contents.devDependencies['ember-load-initializers']; + // This arguable should still exist, but it's a v1 addon + delete contents.devDependencies['ember-cli-deprecation-workflow']; + + // A nice feature of modern apps is using sub-path imports + // Why specify the whole app name, when you can use `#`? + contents.imports = { + '#app/*': './app/*', + '#config': './app/config/environment', + '#components/*': './app/components/*', + }; + } + return stringifyAndNormalize(sortPackageJson(contents)); }, }; diff --git a/tests/minimal.test.mjs b/tests/minimal.test.mjs new file mode 100644 index 00000000..edb86685 --- /dev/null +++ b/tests/minimal.test.mjs @@ -0,0 +1,156 @@ +import { describe, it, expect } from 'vitest'; +import { join } from 'path'; +import { existsSync, writeFileSync } from 'fs'; +import stripAnsi from 'strip-ansi'; +import { newProjectWithFixtures } from './helpers.mjs'; + +const SCENARIOS = [ + { + name: 'no-compat', + flags: ['--no-compat'], + fixturePath: join(import.meta.dirname, 'fixture-gjs-only'), + }, + { + name: 'minimal', + flags: ['--minimal'], + fixturePath: join(import.meta.dirname, 'fixture-gjs-only'), + }, + { + name: 'typescript + no-compat', + flags: ['--typescript', '--no-compat'], + fixturePath: join(import.meta.dirname, 'fixture-gts-only'), + }, + { + name: 'typescript + minimal', + flags: ['--typescript', '--minimal'], + fixturePath: join(import.meta.dirname, 'fixture-gts-only'), + }, +]; + +describe('basic functionality', function () { + for (let { name, flags, packageJson, fixturePath } of SCENARIOS) { + describe(name, function () { + let project = newProjectWithFixtures({ + fixturePath, + flags, + packageJson, + }); + + it('verify files', async function () { + expect( + !existsSync(join(project.dir(), 'app/index.html')), + 'the app index.html has been removed', + ); + expect( + existsSync(join(project.dir(), 'index.html')), + 'the root index.html has been added', + ); + }); + + it('successfully lints', async function () { + let result = await project.execa('pnpm', ['lint']); + + console.log(result.stdout); + }); + + it('successfully builds', async function () { + let result = await project.execa('pnpm', ['build']); + + console.log(result.stdout); + }); + + it('successfully runs tests', async function () { + let result; + + try { + result = await project.execa('pnpm', ['test']); + } catch (err) { + console.log(err.stdout, err.stderr); + throw 'Failed to successfully run test'; + } + + // make sure that each of the tests that we expect actually show up + // alternatively we can change this to search for `pass 3` + expect(result.stdout).to.contain( + 'Acceptance | welcome page: visiting /index shows the welcome page', + ); + expect(result.stdout).to.contain( + 'Acceptance | styles: visiting /styles', + ); + + console.log(result.stdout); + }); + + it('successfully runs tests in dev mode', async function () { + await project.$`pnpm install --save-dev testem http-proxy`; + let appURL; + + let server; + + try { + server = project.execa('pnpm', ['start']); + + await new Promise((resolve) => { + server.stdout.on('data', (line) => { + let result = /Local:\s+(https?:\/\/.*)\//g.exec( + stripAnsi(line.toString()), + ); + + if (result) { + appURL = result[1]; + resolve(); + } + }); + }); + + writeFileSync( + join(project.dir(), 'testem-dev.js'), + `module.exports = { + test_page: 'tests/index.html?hidepassed', + disable_watching: true, + launch_in_ci: ['Chrome'], + launch_in_dev: ['Chrome'], + browser_start_timeout: 120, + browser_args: { + Chrome: { + ci: [ + // --no-sandbox is needed when running Chrome inside a container + process.env.CI ? '--no-sandbox' : null, + '--headless', + '--disable-dev-shm-usage', + '--disable-software-rasterizer', + '--mute-audio', + '--remote-debugging-port=0', + '--window-size=1440,900', + ].filter(Boolean), + }, + }, + middleware: [ + require(__dirname + '/testem-proxy.js')('${appURL}') + ], +}; +`, + ); + + let testResult = await project.execa('pnpm', [ + 'testem', + '--file', + 'testem-dev.js', + 'ci', + ]); + expect(testResult.exitCode).to.eq(0, testResult.output); + } finally { + server?.kill('SIGINT'); + } + }); + + it('successfully optimizes deps', function () { + return project.execa('pnpm', ['vite', 'optimize', '--force']); + }); + + it('can run generators', function () { + return project.execa('pnpm', ['ember', 'g', 'route', 'fancy']); + }); + }); + } +}); From 7c6909bc0ed49fd839500294fae06754245c3406 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Mon, 8 Dec 2025 23:13:14 -0500 Subject: [PATCH 02/12] Remove classicEmberSupport --- files/vite.config.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/vite.config.mjs b/files/vite.config.mjs index 219253db..4d25021f 100644 --- a/files/vite.config.mjs +++ b/files/vite.config.mjs @@ -1,10 +1,10 @@ import { defineConfig } from 'vite'; -import { extensions, classicEmberSupport, ember } from '@embroider/vite'; +import { extensions<% if (!noCompat) { %>, classicEmberSupport<% } %>, ember } from '@embroider/vite'; import { babel } from '@rollup/plugin-babel'; export default defineConfig({ - plugins: [ - classicEmberSupport(), + plugins: [<% if (!noCompat) { %> + classicEmberSupport(),<% } %> ember(), // extra plugins here babel({ From e4d122ff85124eba5f14c2ace10c20652caf17cf Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Mon, 8 Dec 2025 23:16:06 -0500 Subject: [PATCH 03/12] Update lint ignores --- eslint.config.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/eslint.config.mjs b/eslint.config.mjs index 7f3a1fc2..3dbe8a43 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -27,6 +27,7 @@ export default [ { ignores: [ 'tests/fixtures/*', + 'files/vite.config.*', 'files/ember-cli-build.js', 'conditional-files/_js_*', 'conditional-files/_ts_*', From b43790ce30e5139c565c9cc5c1cec5ac8f8a9ae6 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Mon, 8 Dec 2025 23:22:01 -0500 Subject: [PATCH 04/12] Update babel configs --- .../no-compat/_js_babel.config.mjs | 38 +++++++++++++++ .../no-compat/_ts_babel.config.mjs | 46 +++++++++++++++++++ index.js | 9 +++- 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 conditional-files/no-compat/_js_babel.config.mjs create mode 100644 conditional-files/no-compat/_ts_babel.config.mjs diff --git a/conditional-files/no-compat/_js_babel.config.mjs b/conditional-files/no-compat/_js_babel.config.mjs new file mode 100644 index 00000000..bb5b946c --- /dev/null +++ b/conditional-files/no-compat/_js_babel.config.mjs @@ -0,0 +1,38 @@ +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { buildMacros } from '@embroider/macros/babel'; + +const macros = buildMacros(); + +export default { + plugins: [ + [ + 'babel-plugin-ember-template-compilation', + { + compilerPath: 'ember-source/dist/ember-template-compiler.js', + transforms: [...macros.templateMacros], + }, + ], + [ + 'module:decorator-transforms', + { + runtime: { + import: import.meta.resolve('decorator-transforms/runtime-esm'), + }, + }, + ], + [ + '@babel/plugin-transform-runtime', + { + absoluteRuntime: dirname(fileURLToPath(import.meta.url)), + useESModules: true, + regenerator: false, + }, + ], + ...macros.babelMacros, + ], + + generatorOpts: { + compact: false, + }, +}; diff --git a/conditional-files/no-compat/_ts_babel.config.mjs b/conditional-files/no-compat/_ts_babel.config.mjs new file mode 100644 index 00000000..124ffe6a --- /dev/null +++ b/conditional-files/no-compat/_ts_babel.config.mjs @@ -0,0 +1,46 @@ +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { buildMacros } from '@embroider/macros/babel'; + +const macros = buildMacros(); + +export default { + plugins: [ + [ + '@babel/plugin-transform-typescript', + { + allExtensions: true, + onlyRemoveTypeImports: true, + allowDeclareFields: true, + }, + ], + [ + 'babel-plugin-ember-template-compilation', + { + compilerPath: 'ember-source/dist/ember-template-compiler.js', + transforms: [...macros.templateMacros()], + }, + ], + [ + 'module:decorator-transforms', + { + runtime: { + import: import.meta.resolve('decorator-transforms/runtime-esm'), + }, + }, + ], + [ + '@babel/plugin-transform-runtime', + { + absoluteRuntime: dirname(fileURLToPath(import.meta.url)), + useESModules: true, + regenerator: false, + }, + ], + ...macros.babelMacros(), + ], + + generatorOpts: { + compact: false, + }, +}; diff --git a/index.js b/index.js index 489ab07b..ea4fa608 100644 --- a/index.js +++ b/index.js @@ -37,7 +37,14 @@ const replacers = { }, 'babel.config.mjs'(locals) { let prefix = locals.typescript ? '_ts_' : '_js_'; - let filePath = join(CONDITIONAL_FILES, prefix + 'babel.config.mjs'); + + let filePath = join( + [ + CONDITIONAL_FILES, + locals.noCompat && 'no-compat', + prefix + 'babel.config.mjs', + ].filter(Boolean), + ); let raw = readFileSync(filePath).toString(); From 66f80650dda3c0276a0c480d5f1fe93b72fa3dc9 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Mon, 8 Dec 2025 23:31:36 -0500 Subject: [PATCH 05/12] Update the HTMLs --- files/index.html | 11 ++++++----- files/tests/index.html | 14 ++++++++++---- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/files/index.html b/files/index.html index 05f81312..e5b7dd9a 100644 --- a/files/index.html +++ b/files/index.html @@ -5,25 +5,26 @@ <%= namespace %> +<% if (compat) { %> {{content-for "head"}} - {{content-for "head-footer"}} - +<% } %> - {{content-for "body"}} +<% if (compat) { %>{{content-for "body"}} - +<% if (compat) { %>{{content-for "body"}} {{content-for "body-footer"}} - +<% } %> diff --git a/files/tests/index.html b/files/tests/index.html index d90c7b3b..23481b3e 100644 --- a/files/tests/index.html +++ b/files/tests/index.html @@ -5,22 +5,24 @@ <%= namespace %> Tests - +<% if (compat) { %> {{content-for "head"}} {{content-for "test-head"}} - +<% } %> +<% if (compat) { %> {{content-for "head-footer"}} {{content-for "test-head-footer"}} - + <% } %> +<% if (compat) { %> {{content-for "body"}} {{content-for "test-body"}} -
+ <% } %>
@@ -28,8 +30,10 @@
+<% if (compat) { %> +<% } %> +<% if (compat) { %> {{content-for "body-footer"}} +<% } %> From e56bceb08acab9c9fc45e88fa86825690c38e5e4 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Mon, 8 Dec 2025 23:35:51 -0500 Subject: [PATCH 06/12] Update app.ts --- files/app/app.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/files/app/app.ts b/files/app/app.ts index c0871d2c..f04a51ac 100644 --- a/files/app/app.ts +++ b/files/app/app.ts @@ -1,15 +1,18 @@ <% if (warpDrive) { %>import '@warp-drive/ember/install';<% } %> import Application from '@ember/application'; import compatModules from '@embroider/virtual/compat-modules'; -import Resolver from 'ember-resolver'; -import loadInitializers from 'ember-load-initializers'; -import config from '<%= modulePrefix %>/config/environment'; -import { importSync, isDevelopingApp, macroCondition } from '@embroider/macros'; +import Resolver from 'ember-resolver';<% if (compat) { %> +import loadInitializers from 'ember-load-initializers';<% } %> +import config from '<%= modulePrefix %>/config/environment';<% if (notMinimal) { %> +import { importSync, isDevelopingApp, macroCondition } from '@embroider/macros';< } %> import setupInspector from '@embroider/legacy-inspector-support/ember-source-4.12'; +<% if (notMinimal) { %> if (macroCondition(isDevelopingApp())) { importSync('./deprecation-workflow'); } +<% } %> + export default class App extends Application { modulePrefix = config.modulePrefix; @@ -17,5 +20,6 @@ export default class App extends Application { Resolver = Resolver.withModules(compatModules); inspector = setupInspector(this); } - +<% if (compat) { %> loadInitializers(App, config.modulePrefix, compatModules); +<% } %> From c02501a3b15e48856d31b4b1aac4986f43e7c305 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Mon, 8 Dec 2025 23:40:47 -0500 Subject: [PATCH 07/12] Update the environment.ts --- .../no-compat/app/config/environment.ts | 41 +++++++++++++++++++ index.js | 13 ++++++ 2 files changed, 54 insertions(+) create mode 100644 conditional-files/no-compat/app/config/environment.ts diff --git a/conditional-files/no-compat/app/config/environment.ts b/conditional-files/no-compat/app/config/environment.ts new file mode 100644 index 00000000..f0360537 --- /dev/null +++ b/conditional-files/no-compat/app/config/environment.ts @@ -0,0 +1,41 @@ +<% if (notMinimal) { %> +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-expect-error +import { getGlobalConfig } from '@embroider/macros/src/addon/runtime'; +<% } %> + +interface Config { + isTesting?: boolean; + environment: string; + modulePrefix: string; + podModulePrefix?: string; + locationType: 'history' | 'hash' | 'none' | 'auto'; + rootURL: string; + EmberENV?: Record; + APP: Record & { rootElement?: string; autoboot?: boolean }; +} + +const ENV: Config = { + modulePrefix: '<%= name %>', + environment: import.meta.env.DEV ? 'development' : 'production', + rootURL: '/', + locationType: 'history', + EmberENV: {}, + APP: {}, +}; + +export default ENV; + +<% if (notMinimal) { %> +export function enterTestMode() { + ENV.locationType = 'none'; + ENV.APP.rootElement = '#ember-testing'; + ENV.APP.autoboot = false; + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + const config = getGlobalConfig()['@embroider/macros']; + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if (config) config.isTesting = true; +} +<% } %> diff --git a/index.js b/index.js index ea4fa608..0ba96758 100644 --- a/index.js +++ b/index.js @@ -24,6 +24,19 @@ function stringifyAndNormalize(contents) { * (see `conditional-files`) */ const replacers = { + 'app/config/environment.ts'(locals, contents) { + if (locals.noCompat) { + let filePath = join( + CONDITIONAL_FILES, + 'no-compat', + 'app/config/environment.ts', + ); + let raw = readFileSync(filePath).toString(); + return ejs.render(raw, locals); + } + + return contents; + }, 'package.json'(...args) { return this.updatePackageJson(...args); }, From 957318d922cc440f6f7f975f78611bf566813865 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Mon, 8 Dec 2025 23:44:39 -0500 Subject: [PATCH 08/12] Update app -- wow so messy --- files/app/app.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/files/app/app.ts b/files/app/app.ts index f04a51ac..aed1c984 100644 --- a/files/app/app.ts +++ b/files/app/app.ts @@ -1,8 +1,9 @@ -<% if (warpDrive) { %>import '@warp-drive/ember/install';<% } %> +<% if (warpDrive) { %>import '@warp-drive/ember/install';<% } %><% if (compat) { %> import Application from '@ember/application'; import compatModules from '@embroider/virtual/compat-modules'; -import Resolver from 'ember-resolver';<% if (compat) { %> -import loadInitializers from 'ember-load-initializers';<% } %> +import Resolver from 'ember-resolver'; +import loadInitializers from 'ember-load-initializers';<% } else { %> + import Application from 'ember-strict-application-resolver';<% } %> import config from '<%= modulePrefix %>/config/environment';<% if (notMinimal) { %> import { importSync, isDevelopingApp, macroCondition } from '@embroider/macros';< } %> import setupInspector from '@embroider/legacy-inspector-support/ember-source-4.12'; @@ -15,10 +16,16 @@ if (macroCondition(isDevelopingApp())) { export default class App extends Application { - modulePrefix = config.modulePrefix; +<% if (compat) {%> modulePrefix = config.modulePrefix; podModulePrefix = config.podModulePrefix; Resolver = Resolver.withModules(compatModules); - inspector = setupInspector(this); +<% } %> inspector = setupInspector(this); +<% if (noCompat) { %> + modules = { + ...import.meta.glob('./router', { eager: true }), + ...import.meta.glob('./templates/**/*', { eager: true }), + } +<% } %> } <% if (compat) { %> loadInitializers(App, config.modulePrefix, compatModules); From 0ce0641203bf86ab96a4fdf50b8475b379c347e5 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Mon, 8 Dec 2025 23:46:31 -0500 Subject: [PATCH 09/12] Update package --- index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.js b/index.js index 0ba96758..cc034a27 100644 --- a/index.js +++ b/index.js @@ -357,6 +357,8 @@ module.exports = { '#config': './app/config/environment', '#components/*': './app/components/*', }; + + contents.devDependencies['ember-strict-application-resolver'] = '^0.1.0'; } return stringifyAndNormalize(sortPackageJson(contents)); From bfb8c45c1d79f3e224436c7b8350518ef3e4654a Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Mon, 8 Dec 2025 23:54:02 -0500 Subject: [PATCH 10/12] Use conditional-files to clean up the no-compat variance --- conditional-files/no-compat/app/app.ts | 20 ++++++++++++++++++++ files/app/app.ts | 25 +++++++------------------ index.js | 9 +++++++++ 3 files changed, 36 insertions(+), 18 deletions(-) create mode 100644 conditional-files/no-compat/app/app.ts diff --git a/conditional-files/no-compat/app/app.ts b/conditional-files/no-compat/app/app.ts new file mode 100644 index 00000000..5cf7e4da --- /dev/null +++ b/conditional-files/no-compat/app/app.ts @@ -0,0 +1,20 @@ +<% if (warpDrive) { %>import '@warp-drive/ember/install'; +import Application from 'ember-strict-application-resolver'; +import config from '<%= modulePrefix %>/config/environment';<% if (notMinimal) { %> +import { importSync, isDevelopingApp, macroCondition } from '@embroider/macros';< } %> +import setupInspector from '@embroider/legacy-inspector-support/ember-source-4.12'; + +<% if (notMinimal) { %> +if (macroCondition(isDevelopingApp())) { + importSync('./deprecation-workflow'); +} +<% } %> + + +export default class App extends Application { + modules = { + ...import.meta.glob('./router.*', { eager: true }), + ...import.meta.glob('./templates/**/*', { eager: true }), + ...import.meta.glob('./services/**/*', { eager: true }), + } +} diff --git a/files/app/app.ts b/files/app/app.ts index aed1c984..c0871d2c 100644 --- a/files/app/app.ts +++ b/files/app/app.ts @@ -1,32 +1,21 @@ -<% if (warpDrive) { %>import '@warp-drive/ember/install';<% } %><% if (compat) { %> +<% if (warpDrive) { %>import '@warp-drive/ember/install';<% } %> import Application from '@ember/application'; import compatModules from '@embroider/virtual/compat-modules'; import Resolver from 'ember-resolver'; -import loadInitializers from 'ember-load-initializers';<% } else { %> - import Application from 'ember-strict-application-resolver';<% } %> -import config from '<%= modulePrefix %>/config/environment';<% if (notMinimal) { %> -import { importSync, isDevelopingApp, macroCondition } from '@embroider/macros';< } %> +import loadInitializers from 'ember-load-initializers'; +import config from '<%= modulePrefix %>/config/environment'; +import { importSync, isDevelopingApp, macroCondition } from '@embroider/macros'; import setupInspector from '@embroider/legacy-inspector-support/ember-source-4.12'; -<% if (notMinimal) { %> if (macroCondition(isDevelopingApp())) { importSync('./deprecation-workflow'); } -<% } %> - export default class App extends Application { -<% if (compat) {%> modulePrefix = config.modulePrefix; + modulePrefix = config.modulePrefix; podModulePrefix = config.podModulePrefix; Resolver = Resolver.withModules(compatModules); -<% } %> inspector = setupInspector(this); -<% if (noCompat) { %> - modules = { - ...import.meta.glob('./router', { eager: true }), - ...import.meta.glob('./templates/**/*', { eager: true }), - } -<% } %> + inspector = setupInspector(this); } -<% if (compat) { %> + loadInitializers(App, config.modulePrefix, compatModules); -<% } %> diff --git a/index.js b/index.js index cc034a27..719159ca 100644 --- a/index.js +++ b/index.js @@ -24,6 +24,15 @@ function stringifyAndNormalize(contents) { * (see `conditional-files`) */ const replacers = { + 'app/app.ts'(locals, contents) { + if (locals.noCompat) { + let filePath = join(CONDITIONAL_FILES, 'no-compat', 'app/app.ts'); + let raw = readFileSync(filePath).toString(); + return ejs.render(raw, locals); + } + + return contents; + }, 'app/config/environment.ts'(locals, contents) { if (locals.noCompat) { let filePath = join( From 35684ef2ae62b84d3734cddcd05e88e1daf9c25d Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Tue, 9 Dec 2025 15:56:27 -0500 Subject: [PATCH 11/12] ope --- package.json | 1 + pnpm-lock.yaml | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/package.json b/package.json index 41fc20c0..e41b07a4 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "ejs": "^3.1.10", "ember-cli-string-utils": "^1.1.0", "lodash": "^4.17.21", + "sort-package-json": "^3.5.1", "walk-sync": "^3.0.0" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8bdc9a8a..3479e1c5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ importers: lodash: specifier: ^4.17.21 version: 4.17.21 + sort-package-json: + specifier: ^3.5.1 + version: 3.5.1 walk-sync: specifier: ^3.0.0 version: 3.0.0 @@ -1642,6 +1645,10 @@ packages: resolution: {integrity: sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==} engines: {node: '>=12.20'} + detect-indent@7.0.2: + resolution: {integrity: sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A==} + engines: {node: '>=12.20'} + detect-newline@4.0.1: resolution: {integrity: sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -2152,6 +2159,9 @@ packages: git-hooks-list@3.2.0: resolution: {integrity: sha512-ZHG9a1gEhUMX1TvGrLdyWb9kDopCBbTnI8z4JgRMYxsijWipgjSEYoPWqBuIB0DnRnvqlQSEeVmzpeuPm7NdFQ==} + git-hooks-list@4.1.1: + resolution: {integrity: sha512-cmP497iLq54AZnv4YRAEMnEyQ1eIn4tGKbmswqwmFV4GBnAqE8NLtWxxdXa++AalfgL5EBH4IxTPyquEuGY/jA==} + git-repo-info@2.1.1: resolution: {integrity: sha512-8aCohiDo4jwjOwma4FmYFd3i97urZulL8XL24nIPxuE+GZnfsAyy/g2Shqx6OjUiFKUXZM+Yy+KHnOmmA3FVcg==} engines: {node: '>= 4.0'} @@ -3520,6 +3530,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + send@0.19.0: resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} @@ -3635,10 +3650,18 @@ packages: sort-object-keys@1.1.3: resolution: {integrity: sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==} + sort-object-keys@2.0.1: + resolution: {integrity: sha512-R89fO+z3x7hiKPXX5P0qim+ge6Y60AjtlW+QQpRozrrNcR1lw9Pkpm5MLB56HoNvdcLHL4wbpq16OcvGpEDJIg==} + sort-package-json@2.15.1: resolution: {integrity: sha512-9x9+o8krTT2saA9liI4BljNjwAbvUnWf11Wq+i/iZt8nl2UGYnf3TH5uBydE7VALmP7AGwlfszuEeL8BDyb0YA==} hasBin: true + sort-package-json@3.5.1: + resolution: {integrity: sha512-LfwyHQuTnJ3336Sexi6yDz1QxvSjXKbc78pOw2HQy8BJHFXzONu+zLvLald0NpLWM0exsYyI7M8PeJAngNgpbA==} + engines: {node: '>=20'} + hasBin: true + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -5798,6 +5821,8 @@ snapshots: detect-indent@7.0.1: {} + detect-indent@7.0.2: {} + detect-newline@4.0.1: {} diff@7.0.0: {} @@ -6618,6 +6643,8 @@ snapshots: git-hooks-list@3.2.0: {} + git-hooks-list@4.1.1: {} + git-repo-info@2.1.1: {} github-changelog@2.1.2: @@ -8023,6 +8050,8 @@ snapshots: semver@7.7.1: {} + semver@7.7.3: {} + send@0.19.0: dependencies: debug: 2.6.9 @@ -8198,6 +8227,8 @@ snapshots: sort-object-keys@1.1.3: {} + sort-object-keys@2.0.1: {} + sort-package-json@2.15.1: dependencies: detect-indent: 7.0.1 @@ -8209,6 +8240,16 @@ snapshots: sort-object-keys: 1.1.3 tinyglobby: 0.2.13 + sort-package-json@3.5.1: + dependencies: + detect-indent: 7.0.2 + detect-newline: 4.0.1 + git-hooks-list: 4.1.1 + is-plain-obj: 4.1.0 + semver: 7.7.3 + sort-object-keys: 2.0.1 + tinyglobby: 0.2.15 + source-map-js@1.2.1: {} source-map-resolve@0.5.3: From 5d34dde8a8f71e09f6921e62a863f79feddc7ad6 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Tue, 9 Dec 2025 15:56:47 -0500 Subject: [PATCH 12/12] progress --- .gitignore | 1 + .../minimal/app/templates/application.gts | 7 +++++++ conditional-files/no-compat/app/app.ts | 4 ++-- files/app/templates/application.gts | 1 + index.js | 19 ++++++++++++++++--- package.json | 3 ++- 6 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 conditional-files/minimal/app/templates/application.gts diff --git a/.gitignore b/.gitignore index 2ccbe465..f2c0271d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /node_modules/ +/my-app/ diff --git a/conditional-files/minimal/app/templates/application.gts b/conditional-files/minimal/app/templates/application.gts new file mode 100644 index 00000000..dca7d7b7 --- /dev/null +++ b/conditional-files/minimal/app/templates/application.gts @@ -0,0 +1,7 @@ + + diff --git a/conditional-files/no-compat/app/app.ts b/conditional-files/no-compat/app/app.ts index 5cf7e4da..60c1f1c2 100644 --- a/conditional-files/no-compat/app/app.ts +++ b/conditional-files/no-compat/app/app.ts @@ -1,7 +1,7 @@ <% if (warpDrive) { %>import '@warp-drive/ember/install'; -import Application from 'ember-strict-application-resolver'; +<% } %>import Application from 'ember-strict-application-resolver'; import config from '<%= modulePrefix %>/config/environment';<% if (notMinimal) { %> -import { importSync, isDevelopingApp, macroCondition } from '@embroider/macros';< } %> +import { importSync, isDevelopingApp, macroCondition } from '@embroider/macros';<% } %> import setupInspector from '@embroider/legacy-inspector-support/ember-source-4.12'; <% if (notMinimal) { %> diff --git a/files/app/templates/application.gts b/files/app/templates/application.gts index 0a4d1f9e..4727d1bc 100644 --- a/files/app/templates/application.gts +++ b/files/app/templates/application.gts @@ -1,6 +1,7 @@ import { pageTitle } from 'ember-page-title'; <% if (welcome) {%>import { WelcomePage } from 'ember-welcome-page';<% } %> +