diff --git a/packages/compat/src/compat-adapters/@glimmer/tracking.ts b/packages/compat/src/compat-adapters/@glimmer/tracking.ts new file mode 100644 index 000000000..5286aece6 --- /dev/null +++ b/packages/compat/src/compat-adapters/@glimmer/tracking.ts @@ -0,0 +1,34 @@ +import V1Addon from '../../v1-addon'; +import Plugin from 'broccoli-plugin'; +import { join } from 'path'; +import { outputFileSync, copyFileSync } from 'fs-extra'; + +/* + @glimmer/tracking is a real package but it has no working implementation. The + real implementation is in ember-source. + + Since embroider prioritizes real packages, it's best to provide a compat + adapter here to make it into a valid package. It's easy enough for it to + reexport the things from ember that are needed. +*/ +class RedirectToEmber extends Plugin { + private didBuild = false; + + build() { + if (!this.didBuild) { + copyFileSync(join(this.inputPaths[0], 'package.json'), join(this.outputPath, 'package.json')); + outputFileSync(join(this.outputPath, 'index.js'), `export { tracked } from '@ember/-internals/metal';`); + outputFileSync( + join(this.outputPath, 'primitives', 'cache.js'), + `export { createCache, getValue, isConst } from "@ember/-internals/metal";` + ); + this.didBuild = true; + } + } +} + +export default class extends V1Addon { + get v2Tree() { + return new RedirectToEmber([super.v2Tree]); + } +} diff --git a/packages/compat/src/compat-adapters/ember-cli-fastboot.ts b/packages/compat/src/compat-adapters/ember-cli-fastboot.ts index 6370dfbbf..2a1fe1f04 100644 --- a/packages/compat/src/compat-adapters/ember-cli-fastboot.ts +++ b/packages/compat/src/compat-adapters/ember-cli-fastboot.ts @@ -6,6 +6,7 @@ import { join } from 'path'; import writeFile from 'broccoli-file-creator'; import { Memoize } from 'typescript-memoize'; import bind from 'bind-decorator'; +import { AddonMeta } from '@embroider/shared-internals'; export default class EmberCliFastboot extends V1Addon { customizes(...trees: string[]): boolean { @@ -141,6 +142,17 @@ class RewriteManifest extends Plugin { extraVendorFiles, }; + // because we contain a subdir with its own package.json, that subdir + // becomes a "package" from emroider's perspective, and if we want it to get + // treated as ember code it needs to have v2 addon metadata + json.keywords = [...(json.keywords ?? []), 'ember-addon']; + let meta: AddonMeta = { + type: 'addon', + version: 2, + 'auto-upgraded': true, + }; + json['ember-addon'] = meta; + outputJSONSync(join(this.outputPath, '_fastboot_', 'package.json'), json, { spaces: 2 }); } } diff --git a/packages/compat/src/compat-adapters/ember-source.ts b/packages/compat/src/compat-adapters/ember-source.ts index 98b1802fd..7d3af017d 100644 --- a/packages/compat/src/compat-adapters/ember-source.ts +++ b/packages/compat/src/compat-adapters/ember-source.ts @@ -1,80 +1,9 @@ import V1Addon from '../v1-addon'; import buildFunnel from 'broccoli-funnel'; import mergeTrees from 'broccoli-merge-trees'; -import AddToTree from '../add-to-tree'; -import { outputFileSync, unlinkSync } from 'fs-extra'; -import { join } from 'path'; -import semver from 'semver'; export default class extends V1Addon { - private useRealModules = semver.satisfies(this.packageJSON.version, '>=3.27.0-beta.0', { includePrerelease: true }); - get v2Tree() { return mergeTrees([super.v2Tree, buildFunnel(this.rootTree, { include: ['dist/ember-template-compiler.js'] })]); } - - // when using real modules, we're replacing treeForAddon and treeForVendor - customizes(treeName: string) { - return ( - (this.useRealModules && (treeName === 'treeForAddon' || treeName === 'treeForVendor')) || - super.customizes(treeName) - ); - } - - invokeOriginalTreeFor(name: string, opts: { neuterPreprocessors: boolean } = { neuterPreprocessors: false }) { - if (this.useRealModules) { - if (name === 'addon') { - return this.customAddonTree(); - } - if (name === 'vendor') { - return this.customVendorTree(); - } - } - return super.invokeOriginalTreeFor(name, opts); - } - - // Our addon tree is all of the "packages" we share. @embroider/compat already - // supports that pattern of emitting modules into other package's namespaces. - private customAddonTree() { - return mergeTrees([ - buildFunnel(this.rootTree, { - srcDir: 'dist/packages', - }), - buildFunnel(this.rootTree, { - srcDir: 'dist/dependencies', - }), - ]); - } - - // We're zeroing out these files in vendor rather than deleting them, because - // we can't easily intercept the `app.import` that presumably exists for them, - // so rather than error they will just be empty. - // - // The reason we're zeroing these out is that we're going to consume all our - // modules directly out of treeForAddon instead, as real modules that webpack - // can see. - private customVendorTree() { - return new AddToTree(this.addonInstance._treeFor('vendor'), outputPath => { - unlinkSync(join(outputPath, 'ember', 'ember.js')); - outputFileSync(join(outputPath, 'ember', 'ember.js'), ''); - unlinkSync(join(outputPath, 'ember', 'ember-testing.js')); - outputFileSync(join(outputPath, 'ember', 'ember-testing.js'), ''); - }); - } - - get packageMeta() { - let meta = super.packageMeta; - if (this.useRealModules) { - if (!meta['implicit-modules']) { - meta['implicit-modules'] = []; - } - meta['implicit-modules'].push('./ember/index.js'); - - if (!meta['implicit-test-modules']) { - meta['implicit-test-modules'] = []; - } - meta['implicit-test-modules'].push('./ember-testing/index.js'); - } - return meta; - } } diff --git a/packages/core/src/app.ts b/packages/core/src/app.ts index 9af58d52e..34b56179f 100644 --- a/packages/core/src/app.ts +++ b/packages/core/src/app.ts @@ -910,11 +910,14 @@ export class AppBuilder { } private combinePackageJSON(meta: AppMeta): object { - let pkgLayers = [this.app.packageJSON, { keywords: ['ember-addon'], 'ember-addon': meta }]; + let pkgLayers: any[] = [this.app.packageJSON]; let fastbootConfig = this.fastbootConfig; if (fastbootConfig) { + // fastboot-specific package.json output is allowed to add to our original package.json pkgLayers.push(fastbootConfig.packageJSON); } + // but our own new v2 app metadata takes precedence over both + pkgLayers.push({ keywords: ['ember-addon'], 'ember-addon': meta }); return combinePackageJSON(...pkgLayers); } @@ -1107,12 +1110,6 @@ export class AppBuilder { } let eagerModules = []; - if (!this.adapter.adjustImportsOptions().emberNeedsModulesPolyfill) { - // when we're running with fake ember modules, vendor.js takes care of - // this bootstrapping. But when we're running with real ember modules, - // it's up to our entrypoint. - eagerModules.push('@ember/-internals/bootstrap'); - } let requiredAppFiles = [this.requiredOtherFiles(appFiles)]; if (!this.options.staticComponents) { @@ -1257,13 +1254,6 @@ export class AppBuilder { explicitRelative(dirname(myName), this.topAppJSAsset(engines, prepared).relativePath), ]; - if (!this.adapter.adjustImportsOptions().emberNeedsModulesPolyfill) { - // when we're running with fake ember modules, the prebuilt test-support - // script takes care of this bootstrapping. But when we're running with - // real ember modules, it's up to our entrypoint. - eagerModules.push('ember-testing'); - } - let amdModules: { runtime: string; buildtime: string }[] = []; // this is a backward-compatibility feature: addons can force inclusion of // test support modules. diff --git a/packages/router/config/ember-try.js b/packages/router/config/ember-try.js index 96f65c13b..9b5d6a339 100644 --- a/packages/router/config/ember-try.js +++ b/packages/router/config/ember-try.js @@ -39,22 +39,6 @@ module.exports = function () { }, }, }, - { - name: 'ember-beta', - npm: { - devDependencies: { - 'ember-source': urls[1], - }, - }, - }, - { - name: 'ember-canary', - npm: { - devDependencies: { - 'ember-source': urls[2], - }, - }, - }, ], }; }); diff --git a/packages/shared-internals/src/ember-standard-modules.ts b/packages/shared-internals/src/ember-standard-modules.ts index e8222aed0..ab3d6fa7d 100644 --- a/packages/shared-internals/src/ember-standard-modules.ts +++ b/packages/shared-internals/src/ember-standard-modules.ts @@ -24,7 +24,7 @@ export const emberVirtualPackages = new Set(mappings.map((m: any) => m.m // makes the migration from v1 to v2 addons more painful than necessary, because // a v1 addon in between the app and a v2 addon might not declare the peerDep, // breaking the deeper v2 addon. -export const emberVirtualPeerDeps = new Set(['@glimmer/component']); +export const emberVirtualPeerDeps = new Set(['@glimmer/component', '@glimmer/tracking']); // this is a real package, even though it's still listed in rfc176 emberVirtualPackages.delete('@ember/string'); diff --git a/packages/util/config/ember-try.js b/packages/util/config/ember-try.js index b4d3235ff..9534f6aa9 100644 --- a/packages/util/config/ember-try.js +++ b/packages/util/config/ember-try.js @@ -47,22 +47,6 @@ module.exports = async function () { }, }, }, - { - name: 'ember-beta', - npm: { - devDependencies: { - 'ember-source': await getChannelURL('beta'), - }, - }, - }, - { - name: 'ember-canary', - npm: { - devDependencies: { - 'ember-source': await getChannelURL('canary'), - }, - }, - }, { name: 'ember-default-with-jquery', env: {