From a4ce69e0529e7138aeb0b62d2aff948d38977693 Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Thu, 25 Mar 2021 00:25:02 -0400 Subject: [PATCH 01/14] [wip] v2 shim --- .eslintignore | 2 ++ packages/compat/src/compat-addons.ts | 23 ++++++++----- .../core/src/babel-plugin-adjust-imports.ts | 6 ++++ packages/util/.eslintignore | 2 ++ packages/util/.eslintrc.js | 27 ++++++++++++++- packages/util/.gitignore | 3 ++ packages/util/addon-main.js | 5 +++ packages/util/package.json | 6 +++- packages/util/src/shim.ts | 34 +++++++++++++++++++ 9 files changed, 98 insertions(+), 10 deletions(-) create mode 100644 packages/util/addon-main.js create mode 100644 packages/util/src/shim.ts diff --git a/.eslintignore b/.eslintignore index a981add70..da48df3f3 100644 --- a/.eslintignore +++ b/.eslintignore @@ -6,6 +6,8 @@ /packages/compat/**/*.d.ts /packages/macros/**/*.js /packages/macros/**/*.d.ts +/packages/util/src/**/*.js +/packages/util/src/**/*.d.ts /packages/webpack/**/*.js /packages/webpack/**/*.d.ts /packages/hbs-loader/**/*.js diff --git a/packages/compat/src/compat-addons.ts b/packages/compat/src/compat-addons.ts index dba557c1f..99ea6358d 100644 --- a/packages/compat/src/compat-addons.ts +++ b/packages/compat/src/compat-addons.ts @@ -1,5 +1,5 @@ import { Node } from 'broccoli-node-api'; -import { join, relative, dirname } from 'path'; +import { join, relative, dirname, isAbsolute } from 'path'; import { emptyDirSync, ensureSymlinkSync, ensureDirSync, realpathSync, copySync, writeJSONSync } from 'fs-extra'; import { Stage, Package, PackageCache, WaitForTrees, mangledEngineRoot } from '@embroider/core'; import V1InstanceCache from './v1-instance-cache'; @@ -111,14 +111,21 @@ export default class CompatAddons implements Stage { if (!treeInstance) { let ignore = ['**/node_modules']; - if (join(destination, 'tests', 'dummy') === this.appDestDir) { - // special case: we're building the dummy app of this addon. Because - // the dummy app is nested underneath the addon, we need to tell our - // TreeSync to ignore it. Not because it's ever present at our input, - // but because stage2 will make it appear inside our output and we - // should leave that alone. - ignore.push('tests'); + + let rel = relative(destination, this.appDestDir); + if (!rel.startsWith('..') && !isAbsolute(rel)) { + // the app is inside our addon. We must not copy the app as part of + // the addon, because that would overwrite the real app build. + ignore.push(rel); + + if (rel === 'tests/dummy') { + // special case: classic dummy apps are weird because they put the + // tests (which are truly part of the app, not the addon) inside the + // addon instead of inside the app. + ignore.push('tests'); + } } + treeInstance = new TreeSync(movedAddons[index], destination, { ignore, }); diff --git a/packages/core/src/babel-plugin-adjust-imports.ts b/packages/core/src/babel-plugin-adjust-imports.ts index 71bcec0bf..e3c3f77dd 100644 --- a/packages/core/src/babel-plugin-adjust-imports.ts +++ b/packages/core/src/babel-plugin-adjust-imports.ts @@ -227,6 +227,12 @@ function handleExternal(specifier: string, sourceFile: AdjustFile, opts: Options let relocatedPkg = sourceFile.relocatedIntoPackage(); if (relocatedPkg) { // this file has been moved into another package (presumably the app). + + // self-imports are legal in the app tree, even for v2 packages + if (packageName === pkg.name) { + return specifier; + } + // first try to resolve from the destination package if (isResolvable(packageName, relocatedPkg)) { if (!pkg.meta['auto-upgraded']) { diff --git a/packages/util/.eslintignore b/packages/util/.eslintignore index 922165552..09d7628dd 100644 --- a/packages/util/.eslintignore +++ b/packages/util/.eslintignore @@ -5,6 +5,8 @@ # compiled output /dist/ /tmp/ +/src/**/*.js +/src/**/*.d.ts # dependencies /bower_components/ diff --git a/packages/util/.eslintrc.js b/packages/util/.eslintrc.js index 50b6a0865..f70971529 100644 --- a/packages/util/.eslintrc.js +++ b/packages/util/.eslintrc.js @@ -27,7 +27,7 @@ module.exports = { '.prettierrc.js', '.template-lintrc.js', 'ember-cli-build.js', - 'index.js', + 'addon-main.js', 'testem.js', 'blueprints/*/index.js', 'config/**/*.js', @@ -49,5 +49,30 @@ module.exports = { plugins: ['node'], extends: ['plugin:node/recommended'], }, + // node typescript files + { + files: ['src/**/*.ts'], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: 2017, + sourceType: 'module', + }, + plugins: ['@typescript-eslint'], + extends: ['prettier/@typescript-eslint'], + rules: { + '@typescript-eslint/naming-convention': [ + 'error', + { + selector: 'typeLike', + format: ['PascalCase'], + }, + ], + '@typescript-eslint/consistent-type-assertions': 'error', + '@typescript-eslint/no-inferrable-types': 'error', + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + 'no-unused-vars': 'off', + '@typescript-eslint/no-require-imports': 'error', + }, + }, ], }; diff --git a/packages/util/.gitignore b/packages/util/.gitignore index 7e0f7ddce..008bca93c 100644 --- a/packages/util/.gitignore +++ b/packages/util/.gitignore @@ -3,6 +3,9 @@ # compiled output /dist/ /tmp/ +/src/**/*.js +/src/**/*.d.ts +/src/**/*.map # dependencies /bower_components/ diff --git a/packages/util/addon-main.js b/packages/util/addon-main.js new file mode 100644 index 000000000..0ca063d42 --- /dev/null +++ b/packages/util/addon-main.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = { + name: require('./package').name, +}; diff --git a/packages/util/package.json b/packages/util/package.json index 8254fcfda..313f99f31 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -13,6 +13,7 @@ "test": "tests" }, "scripts": { + "prepare": "tsc", "build": "ember build --environment=production", "lint": "npm-run-all --aggregate-output --continue-on-error --parallel 'lint:!(fix)'", "lint:fix": "npm-run-all --aggregate-output --continue-on-error --parallel lint:*:fix", @@ -40,6 +41,8 @@ "@embroider/webpack": "0.37.0", "@glimmer/component": "^1.0.3", "@glimmer/tracking": "^1.0.3", + "@typescript-eslint/eslint-plugin": "^4.1.1", + "@typescript-eslint/parser": "^4.1.1", "babel-eslint": "^10.1.0", "broccoli-asset-rev": "^3.0.0", "ember-auto-import": "^1.10.1", @@ -78,7 +81,8 @@ "edition": "octane" }, "ember-addon": { - "configPath": "tests/dummy/config" + "configPath": "tests/dummy/config", + "main": "addon-main.js" }, "volta": { "extends": "../../package.json" diff --git a/packages/util/src/shim.ts b/packages/util/src/shim.ts new file mode 100644 index 000000000..1a7414529 --- /dev/null +++ b/packages/util/src/shim.ts @@ -0,0 +1,34 @@ +import { resolve } from 'path'; +import { readFileSync } from 'fs'; + +export interface ShimOptions { + testApp?: string; +} + +export function addonV2toV1Shim(directory: string, options: ShimOptions = {}) { + let pkg = JSON.parse(readFileSync(resolve(directory, './package.json'), 'utf8')); + return { + name: pkg.name, + treeForApp(this: AddonInstance) { + let appJS = pkg['ember-addon']?.['app-js']; + if (appJS) { + return this.treeGenerator(resolve(directory, appJS)); + } + }, + treeForAddon() { + return undefined; + }, + isDevelopingAddon(this: AddonInstance) { + if (options.testApp) { + let appInstance = this._findHost(); + return appInstance.project.root === resolve(directory, options.testApp); + } + }, + }; +} + +// minimal types to cover the parts of the Addon instance that we touch +interface AddonInstance { + _findHost(): { project: { root: string } }; + treeGenerator(dir: string): unknown; +} From 6defb9162a2391141ae13ce562d622fbcdf40952 Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Thu, 25 Mar 2021 15:46:14 -0400 Subject: [PATCH 02/14] exposing shim module separately Because it is for use in node, and the rest is for use in the browser. --- packages/util/package.json | 4 ++++ packages/util/src/shim.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/util/package.json b/packages/util/package.json index 313f99f31..ae8fd4290 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -8,6 +8,10 @@ "repository": "", "license": "MIT", "author": "", + "exports": { + "./shim": "./src/shim.js", + "./addon-main": "./src/shim.js" + }, "directories": { "doc": "doc", "test": "tests" diff --git a/packages/util/src/shim.ts b/packages/util/src/shim.ts index 1a7414529..373d91e33 100644 --- a/packages/util/src/shim.ts +++ b/packages/util/src/shim.ts @@ -5,7 +5,7 @@ export interface ShimOptions { testApp?: string; } -export function addonV2toV1Shim(directory: string, options: ShimOptions = {}) { +export function addonV1Shim(directory: string, options: ShimOptions = {}) { let pkg = JSON.parse(readFileSync(resolve(directory, './package.json'), 'utf8')); return { name: pkg.name, From 31995fa1ea17ad5985f565e9b5804efd75b6ea6d Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Sun, 28 Mar 2021 10:00:42 -0400 Subject: [PATCH 03/14] post-merge formatting --- packages/util/src/shim.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/util/src/shim.ts b/packages/util/src/shim.ts index 373d91e33..f333a1ac9 100644 --- a/packages/util/src/shim.ts +++ b/packages/util/src/shim.ts @@ -6,7 +6,9 @@ export interface ShimOptions { } export function addonV1Shim(directory: string, options: ShimOptions = {}) { - let pkg = JSON.parse(readFileSync(resolve(directory, './package.json'), 'utf8')); + let pkg = JSON.parse( + readFileSync(resolve(directory, './package.json'), 'utf8') + ); return { name: pkg.name, treeForApp(this: AddonInstance) { From 725c5268df9a543f948c0d24bf8ab7bd8b0058d0 Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Sun, 28 Mar 2021 11:44:47 -0400 Subject: [PATCH 04/14] expand app-js --- packages/util/package.json | 1 + packages/util/src/shim.ts | 32 +++++++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/packages/util/package.json b/packages/util/package.json index ae8fd4290..ffad732e9 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -33,6 +33,7 @@ }, "dependencies": { "@embroider/macros": "0.37.0", + "broccoli-funnel": "^2.0.1", "ember-cli-babel": "^7.23.1" }, "devDependencies": { diff --git a/packages/util/src/shim.ts b/packages/util/src/shim.ts index f333a1ac9..c1ce911e0 100644 --- a/packages/util/src/shim.ts +++ b/packages/util/src/shim.ts @@ -1,20 +1,46 @@ import { resolve } from 'path'; import { readFileSync } from 'fs'; +import type { AddonMeta } from '@embroider/shared-internals'; +import Funnel from 'broccoli-funnel'; export interface ShimOptions { testApp?: string; } +function addonMeta(pkgJSON: any): AddonMeta { + let meta = pkgJSON['ember-addon']; + if (meta?.version !== 2 || meta?.type !== 'addon') { + throw new Error(`did not find valid v2 addon metadata in ${pkgJSON.name}`); + } + return meta as AddonMeta; +} + export function addonV1Shim(directory: string, options: ShimOptions = {}) { let pkg = JSON.parse( readFileSync(resolve(directory, './package.json'), 'utf8') ); + let meta = addonMeta(pkg); return { name: pkg.name, treeForApp(this: AddonInstance) { - let appJS = pkg['ember-addon']?.['app-js']; - if (appJS) { - return this.treeGenerator(resolve(directory, appJS)); + let maybeAppJS = meta['app-js']; + if (maybeAppJS) { + const appJS = maybeAppJS; + return new Funnel(this.treeGenerator(directory), { + files: Object.values(appJS), + getDestinationPath(relativePath: string): string { + for (let [exteriorName, interiorName] of Object.entries(appJS)) { + if (relativePath === interiorName) { + return exteriorName; + } + } + throw new Error( + `bug in addonV1Shim, no match for ${relativePath} in ${JSON.stringify( + appJS + )}` + ); + }, + }); } }, treeForAddon() { From b0608f6887fdcd6498a277a23a52c4c3a8617aa3 Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Sun, 28 Mar 2021 23:37:12 -0400 Subject: [PATCH 05/14] don't rely on `exports` because node 10 doesn't understand it --- packages/util/.gitignore | 3 +++ packages/util/index.d.ts | 1 - packages/util/index.js | 5 ----- packages/util/package.json | 4 ---- packages/util/{src => }/shim.ts | 0 tsconfig.json | 7 ++++++- 6 files changed, 9 insertions(+), 11 deletions(-) delete mode 100644 packages/util/index.d.ts delete mode 100644 packages/util/index.js rename packages/util/{src => }/shim.ts (100%) diff --git a/packages/util/.gitignore b/packages/util/.gitignore index 008bca93c..3658f9182 100644 --- a/packages/util/.gitignore +++ b/packages/util/.gitignore @@ -6,6 +6,9 @@ /src/**/*.js /src/**/*.d.ts /src/**/*.map +/shim.js +/shim.d.ts +/shim.js.map # dependencies /bower_components/ diff --git a/packages/util/index.d.ts b/packages/util/index.d.ts deleted file mode 100644 index d3ea75f5a..000000000 --- a/packages/util/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -export function ensureSafeComponent(component: unknown, thingWithOwner: unknown): unknown; diff --git a/packages/util/index.js b/packages/util/index.js deleted file mode 100644 index 0ca063d42..000000000 --- a/packages/util/index.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -module.exports = { - name: require('./package').name, -}; diff --git a/packages/util/package.json b/packages/util/package.json index ffad732e9..ef096e268 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -8,10 +8,6 @@ "repository": "", "license": "MIT", "author": "", - "exports": { - "./shim": "./src/shim.js", - "./addon-main": "./src/shim.js" - }, "directories": { "doc": "doc", "test": "tests" diff --git a/packages/util/src/shim.ts b/packages/util/shim.ts similarity index 100% rename from packages/util/src/shim.ts rename to packages/util/shim.ts diff --git a/tsconfig.json b/tsconfig.json index 998f3fef0..51b21e351 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,10 @@ { - "include": ["./packages/*/src/**/*.ts", "./packages/*/tests/**/*.ts", "./test-packages/support/**/*.ts"], + "include": [ + "./packages/*/src/**/*.ts", + "./packages/*/tests/**/*.ts", + "./test-packages/support/**/*.ts", + "./packages/util/shim.ts" + ], "compilerOptions": { "target": "es2017", "module": "commonjs", From 020afc52554de52b3b9247c7e197abc439ba3bcb Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Mon, 29 Mar 2021 01:07:58 -0400 Subject: [PATCH 06/14] moving packageName into shared utilities for use in ember-auto-import --- packages/core/src/babel-plugin-adjust-imports.ts | 2 +- packages/core/src/index.ts | 2 +- packages/shared-internals/src/index.ts | 1 + packages/{core => shared-internals}/src/package-name.ts | 0 4 files changed, 3 insertions(+), 2 deletions(-) rename packages/{core => shared-internals}/src/package-name.ts (100%) diff --git a/packages/core/src/babel-plugin-adjust-imports.ts b/packages/core/src/babel-plugin-adjust-imports.ts index e3c3f77dd..7633165c1 100644 --- a/packages/core/src/babel-plugin-adjust-imports.ts +++ b/packages/core/src/babel-plugin-adjust-imports.ts @@ -1,4 +1,4 @@ -import getPackageName from './package-name'; +import { packageName as getPackageName } from '@embroider/shared-internals'; import { join, dirname, resolve } from 'path'; import { NodePath } from '@babel/traverse'; import type * as t from '@babel/types'; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 24dac9e09..37459a8a2 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -14,7 +14,6 @@ export { Plugins as TemplateCompilerPlugins } from './ember-template-compiler-ty export { Asset, EmberAsset, ImplicitAssetPaths } from './asset'; export { default as Options, optionsWithDefaults } from './options'; export { default as toBroccoliPlugin } from './to-broccoli-plugin'; -export { default as packageName } from './package-name'; export { default as WaitForTrees, OutputPaths } from './wait-for-trees'; export { default as BuildStage } from './build-stage'; export { compile as jsHandlebarsCompile } from './js-handlebars'; @@ -34,4 +33,5 @@ export { V2Package, PackageCache, babelFilter, + packageName, } from '@embroider/shared-internals'; diff --git a/packages/shared-internals/src/index.ts b/packages/shared-internals/src/index.ts index 3cca3b161..c674a26b1 100644 --- a/packages/shared-internals/src/index.ts +++ b/packages/shared-internals/src/index.ts @@ -4,3 +4,4 @@ export { getOrCreate } from './get-or-create'; export { default as Package, V2AddonPackage as AddonPackage, V2AppPackage as AppPackage, V2Package } from './package'; export { default as PackageCache } from './package-cache'; export { default as babelFilter } from './babel-filter'; +export { default as packageName } from './package-name'; diff --git a/packages/core/src/package-name.ts b/packages/shared-internals/src/package-name.ts similarity index 100% rename from packages/core/src/package-name.ts rename to packages/shared-internals/src/package-name.ts From 09d9e7a9c0084270f96db43bf92eab4d1c2fb889 Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Mon, 29 Mar 2021 01:14:17 -0400 Subject: [PATCH 07/14] fixing up linting rules we had to move shim up to the top level because that's the path we want people to import --- packages/util/.eslintignore | 2 ++ packages/util/.eslintrc.js | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/util/.eslintignore b/packages/util/.eslintignore index 09d7628dd..c0287da2c 100644 --- a/packages/util/.eslintignore +++ b/packages/util/.eslintignore @@ -7,6 +7,8 @@ /tmp/ /src/**/*.js /src/**/*.d.ts +/shim.js +/shim.d.ts # dependencies /bower_components/ diff --git a/packages/util/.eslintrc.js b/packages/util/.eslintrc.js index f70971529..0566bd419 100644 --- a/packages/util/.eslintrc.js +++ b/packages/util/.eslintrc.js @@ -51,7 +51,7 @@ module.exports = { }, // node typescript files { - files: ['src/**/*.ts'], + files: ['src/**/*.ts', 'shim.ts'], parser: '@typescript-eslint/parser', parserOptions: { ecmaVersion: 2017, @@ -69,7 +69,10 @@ module.exports = { ], '@typescript-eslint/consistent-type-assertions': 'error', '@typescript-eslint/no-inferrable-types': 'error', - '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + '@typescript-eslint/no-unused-vars': [ + 'error', + { argsIgnorePattern: '^_' }, + ], 'no-unused-vars': 'off', '@typescript-eslint/no-require-imports': 'error', }, From 7e8f5328073bc157c03487aa8310cd8ea3bb4520 Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Mon, 29 Mar 2021 01:51:25 -0400 Subject: [PATCH 08/14] need to fix top-leve lint rules too --- .eslintignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.eslintignore b/.eslintignore index da48df3f3..1172e0271 100644 --- a/.eslintignore +++ b/.eslintignore @@ -8,6 +8,8 @@ /packages/macros/**/*.d.ts /packages/util/src/**/*.js /packages/util/src/**/*.d.ts +/packages/util/shim.js +/packages/util/shim.d.ts /packages/webpack/**/*.js /packages/webpack/**/*.d.ts /packages/hbs-loader/**/*.js From 8ebbf517b62069ffa5af1de677e118f3864f3788 Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Mon, 29 Mar 2021 18:33:16 -0400 Subject: [PATCH 09/14] moving ember-cli-models into shared-internals (from ember-auto-import) --- packages/core/src/index.ts | 17 +----- .../shared-internals/src/ember-cli-models.ts | 55 +++++++++++++++++++ packages/shared-internals/src/index.ts | 1 + 3 files changed, 59 insertions(+), 14 deletions(-) create mode 100644 packages/shared-internals/src/ember-cli-models.ts diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 37459a8a2..f9069d61f 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -21,17 +21,6 @@ export { AppAdapter, AppBuilder, EmberENV } from './app'; export { todo, unsupported, warn, debug, expectWarning, throwOnWarnings } from './messages'; export { mangledEngineRoot } from './engine-mangler'; -export { - AppMeta, - AddonMeta, - explicitRelative, - extensionsPattern, - getOrCreate, - Package, - AddonPackage, - AppPackage, - V2Package, - PackageCache, - babelFilter, - packageName, -} from '@embroider/shared-internals'; +// this is reexported because we already make users manage a peerDep from some +// other packages (like embroider/webpack and @embroider/ +export * from '@embroider/shared-internals'; diff --git a/packages/shared-internals/src/ember-cli-models.ts b/packages/shared-internals/src/ember-cli-models.ts new file mode 100644 index 000000000..f50e25456 --- /dev/null +++ b/packages/shared-internals/src/ember-cli-models.ts @@ -0,0 +1,55 @@ +import type { Node } from 'broccoli-node-api'; +export interface Project { + targets: unknown; + ui: { + write(...args: any[]): void; + }; + pkg: { name: string; version: string }; + root: string; + addons: AddonInstance[]; + name(): string; +} + +export interface AppInstance { + env: 'development' | 'test' | 'production'; + project: Project; + options: any; + addonPostprocessTree: (which: string, tree: Node) => Node; +} + +interface BaseAddonInstance { + project: Project; + pkg: { name: string; version: string }; + root: string; + options: any; + addons: AddonInstance[]; + name: string; + _super: any; + treeGenerator(path: string): Node; + _findHost(): AppInstance; +} + +export interface DeepAddonInstance extends BaseAddonInstance { + // this is how it looks when an addon is beneath another addon + parent: AddonInstance; +} + +export interface ShallowAddonInstance extends BaseAddonInstance { + // this is how it looks when an addon is directly beneath the app + parent: Project; + app: AppInstance; +} + +export type AddonInstance = DeepAddonInstance | ShallowAddonInstance; + +export function isDeepAddonInstance(addon: AddonInstance): addon is DeepAddonInstance { + return addon.parent !== addon.project; +} + +export function findTopmostAddon(addon: AddonInstance): ShallowAddonInstance { + if (isDeepAddonInstance(addon)) { + return findTopmostAddon(addon.parent); + } else { + return addon; + } +} diff --git a/packages/shared-internals/src/index.ts b/packages/shared-internals/src/index.ts index c674a26b1..2ea36ce9f 100644 --- a/packages/shared-internals/src/index.ts +++ b/packages/shared-internals/src/index.ts @@ -5,3 +5,4 @@ export { default as Package, V2AddonPackage as AddonPackage, V2AppPackage as App export { default as PackageCache } from './package-cache'; export { default as babelFilter } from './babel-filter'; export { default as packageName } from './package-name'; +export * from './ember-cli-models'; From 44a9b9cf68a9fe3f0f652469c25ac675536a5b54 Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Mon, 29 Mar 2021 18:49:33 -0400 Subject: [PATCH 10/14] progress on shim --- packages/util/shim.ts | 131 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 119 insertions(+), 12 deletions(-) diff --git a/packages/util/shim.ts b/packages/util/shim.ts index c1ce911e0..26ae52c75 100644 --- a/packages/util/shim.ts +++ b/packages/util/shim.ts @@ -1,10 +1,17 @@ -import { resolve } from 'path'; +import { resolve, relative, isAbsolute } from 'path'; import { readFileSync } from 'fs'; -import type { AddonMeta } from '@embroider/shared-internals'; +import { + AddonMeta, + AddonInstance, + isDeepAddonInstance, +} from '@embroider/shared-internals'; import Funnel from 'broccoli-funnel'; +import type { Node } from 'broccoli-node-api'; + +const MIN_SUPPORT_LEVEL = 1; export interface ShimOptions { - testApp?: string; + disabled?: (options: any) => boolean; } function addonMeta(pkgJSON: any): AddonMeta { @@ -19,14 +26,48 @@ export function addonV1Shim(directory: string, options: ShimOptions = {}) { let pkg = JSON.parse( readFileSync(resolve(directory, './package.json'), 'utf8') ); + let meta = addonMeta(pkg); + let disabled = false; + const rootTrees = new WeakMap(); + + function rootTree(addonInstance: AddonInstance): Node { + let tree = rootTrees.get(addonInstance); + if (!tree) { + tree = addonInstance.treeGenerator(directory); + rootTrees.set(addonInstance, tree); + } + return tree; + } + return { name: pkg.name, + included(this: AddonInstance, ...args: unknown[]) { + this._super.included.apply(this, args); + + ensureAutoImport(this); + + let parentOptions: any; + if (isDeepAddonInstance(this)) { + // our parent is an addon + parentOptions = this.parent.options; + } else { + // our parent is the app + parentOptions = this.app.options; + } + if (options.disabled) { + disabled = options.disabled(parentOptions); + } + }, + treeForApp(this: AddonInstance) { + if (disabled) { + return undefined; + } let maybeAppJS = meta['app-js']; if (maybeAppJS) { const appJS = maybeAppJS; - return new Funnel(this.treeGenerator(directory), { + return new Funnel(rootTree(this), { files: Object.values(appJS), getDestinationPath(relativePath: string): string { for (let [exteriorName, interiorName] of Object.entries(appJS)) { @@ -43,20 +84,86 @@ export function addonV1Shim(directory: string, options: ShimOptions = {}) { }); } }, + treeForAddon() { + // this never goes through broccoli -- it's always pulled into the app via + // ember-auto-import, as needed. This means it always benefits from + // tree-shaking. return undefined; }, - isDevelopingAddon(this: AddonInstance) { - if (options.testApp) { - let appInstance = this._findHost(); - return appInstance.project.root === resolve(directory, options.testApp); + + treeForPublic(this: AddonInstance) { + if (disabled) { + return undefined; + } + let maybeAssets = meta['public-assets']; + if (maybeAssets) { + const assets = maybeAssets; + return new Funnel(rootTree(this), { + files: Object.keys(assets), + getDestinationPath(relativePath: string): string { + for (let [interiorName, exteriorName] of Object.entries(assets)) { + if (relativePath === interiorName) { + return exteriorName; + } + } + throw new Error( + `bug in addonV1Shim, no match for ${relativePath} in ${JSON.stringify( + assets + )}` + ); + }, + }); } }, + + isDevelopingAddon(this: AddonInstance) { + // if the app is inside our own directory, we must be under development. + // This setting controls whether ember-cli will watch for changes in the + // broccoli trees we expose, but it doesn't have any control over our + // files that get auto-imported into the app. For that, you should use + // ember-auto-import's watchDependencies option (and this should become + // part of the blueprint for test apps). + let appInstance = this._findHost(); + return isInside(directory, appInstance.project.root); + }, }; } -// minimal types to cover the parts of the Addon instance that we touch -interface AddonInstance { - _findHost(): { project: { root: string } }; - treeGenerator(dir: string): unknown; +function isInside(parentDir: string, otherDir: string): boolean { + let rel = relative(parentDir, otherDir); + return Boolean(rel) && !rel.startsWith('..') && !isAbsolute(rel); +} + +function ensureAutoImport(instance: AddonInstance) { + let autoImport = instance.parent.addons.find( + (a) => a.name === 'ember-auto-import' + ); + if (!autoImport) { + throw new Error( + `${ + instance.name + } is a v2-formatted addon. To use it without Embroider, the package that depends on it (${parentName( + instance + )}) must have ember-auto-import.` + ); + } + let level = (autoImport as any).v2AddonSupportLevel ?? 0; + if (level < MIN_SUPPORT_LEVEL) { + throw new Error( + `${ + instance.name + } is using v2 addon features that require a newer ember-auto-import than the one that is present in ${parentName( + instance + )}` + ); + } +} + +function parentName(instance: AddonInstance): string { + if (isDeepAddonInstance(instance)) { + return instance.parent.name; + } else { + return instance.parent.name(); + } } From dad9d18938f4b2a4debd4624dec065485c26d056 Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Tue, 30 Mar 2021 11:32:39 -0400 Subject: [PATCH 11/14] upgrading broccoli-funnel To get a newer walkSync, to make it not crash on symlink cycles. Also, I had to fix a bug in broccoli-funnel so this is a fork for now. --- packages/compat/package.json | 2 +- packages/compat/src/add-to-tree.ts | 2 +- packages/compat/src/build-compat-addon.ts | 2 +- .../src/compat-adapters/ember-asset-loader.ts | 2 +- .../compat-adapters/ember-cli-clipboard.ts | 2 +- .../ember-cli-deprecation-workflow.ts | 2 +- .../src/compat-adapters/ember-cli-mirage.ts | 2 +- .../ember-composable-helpers.ts | 2 +- .../src/compat-adapters/ember-source.ts | 2 +- packages/compat/src/modules-compat.ts | 2 +- packages/compat/src/observe-tree.ts | 2 +- packages/compat/src/rewrite-addon-tree.ts | 2 +- packages/compat/src/snitch.ts | 2 +- packages/compat/src/v1-addon.ts | 2 +- packages/compat/src/v1-app.ts | 2 +- packages/util/package.json | 2 +- packages/util/shim.ts | 2 +- test-packages/funky-sample-addon/package.json | 2 +- types/broccoli-funnel/index.d.ts | 5 ++++- yarn.lock | 22 ++++++++++++++----- 20 files changed, 38 insertions(+), 25 deletions(-) diff --git a/packages/compat/package.json b/packages/compat/package.json index 4e069231a..74d5997a1 100644 --- a/packages/compat/package.json +++ b/packages/compat/package.json @@ -40,7 +40,7 @@ "broccoli": "^3.4.2", "broccoli-concat": "^3.7.3", "broccoli-file-creator": "^2.1.1", - "broccoli-funnel": "^2.0.1", + "broccoli-funnel": "ef4/broccoli-funnel#d133c15aa7dd408222b544346ecf76a24c170af1", "broccoli-merge-trees": "^3.0.0", "broccoli-persistent-filter": "^3.1.2", "broccoli-plugin": "^4.0.0", diff --git a/packages/compat/src/add-to-tree.ts b/packages/compat/src/add-to-tree.ts index 12e83a256..9fe1100e7 100644 --- a/packages/compat/src/add-to-tree.ts +++ b/packages/compat/src/add-to-tree.ts @@ -1,5 +1,5 @@ import { Node } from 'broccoli-node-api'; -import Funnel from 'broccoli-funnel'; +import { Funnel } from 'broccoli-funnel'; export default class AddToTree extends Funnel { constructor(combinedVendor: Node, private hook: (outputPath: string) => Promise | void) { diff --git a/packages/compat/src/build-compat-addon.ts b/packages/compat/src/build-compat-addon.ts index 96a7d5bfc..f11396749 100644 --- a/packages/compat/src/build-compat-addon.ts +++ b/packages/compat/src/build-compat-addon.ts @@ -4,7 +4,7 @@ import SmooshPackageJSON from './smoosh-package-json'; import broccoliMergeTrees from 'broccoli-merge-trees'; import { Node } from 'broccoli-node-api'; import OneShot from './one-shot'; -import Funnel from 'broccoli-funnel'; +import { Funnel } from 'broccoli-funnel'; import { UnwatchedDir, WatchedDir } from 'broccoli-source'; import EmptyPackageTree from './empty-package-tree'; diff --git a/packages/compat/src/compat-adapters/ember-asset-loader.ts b/packages/compat/src/compat-adapters/ember-asset-loader.ts index 884d81a9c..3ce173b15 100644 --- a/packages/compat/src/compat-adapters/ember-asset-loader.ts +++ b/packages/compat/src/compat-adapters/ember-asset-loader.ts @@ -1,5 +1,5 @@ import V1Addon from '../v1-addon'; -import Funnel from 'broccoli-funnel'; +import { Funnel } from 'broccoli-funnel'; import cloneDeep from 'lodash/cloneDeep'; // ember-asset-loader's ManifestGenerator (which is used as the Addon base class diff --git a/packages/compat/src/compat-adapters/ember-cli-clipboard.ts b/packages/compat/src/compat-adapters/ember-cli-clipboard.ts index daee5abc3..571070df1 100644 --- a/packages/compat/src/compat-adapters/ember-cli-clipboard.ts +++ b/packages/compat/src/compat-adapters/ember-cli-clipboard.ts @@ -1,6 +1,6 @@ import V1Addon from '../v1-addon'; import { Memoize } from 'typescript-memoize'; -import Funnel from 'broccoli-funnel'; +import { Funnel } from 'broccoli-funnel'; export default class EmberCLIClipboard extends V1Addon { @Memoize() diff --git a/packages/compat/src/compat-adapters/ember-cli-deprecation-workflow.ts b/packages/compat/src/compat-adapters/ember-cli-deprecation-workflow.ts index 3332fdd1c..6de8957fb 100644 --- a/packages/compat/src/compat-adapters/ember-cli-deprecation-workflow.ts +++ b/packages/compat/src/compat-adapters/ember-cli-deprecation-workflow.ts @@ -3,7 +3,7 @@ import { join, dirname } from 'path'; import { UnwatchedDir } from 'broccoli-source'; import resolve from 'resolve'; import { Memoize } from 'typescript-memoize'; -import Funnel from 'broccoli-funnel'; +import { Funnel } from 'broccoli-funnel'; export default class extends V1Addon { @Memoize() diff --git a/packages/compat/src/compat-adapters/ember-cli-mirage.ts b/packages/compat/src/compat-adapters/ember-cli-mirage.ts index ba285eddf..0328ac3ae 100644 --- a/packages/compat/src/compat-adapters/ember-cli-mirage.ts +++ b/packages/compat/src/compat-adapters/ember-cli-mirage.ts @@ -1,5 +1,5 @@ import V1Addon from '../v1-addon'; -import Funnel from 'broccoli-funnel'; +import { Funnel } from 'broccoli-funnel'; import { AddonMeta } from '@embroider/core'; export default class extends V1Addon { diff --git a/packages/compat/src/compat-adapters/ember-composable-helpers.ts b/packages/compat/src/compat-adapters/ember-composable-helpers.ts index d8a52db74..215951baf 100644 --- a/packages/compat/src/compat-adapters/ember-composable-helpers.ts +++ b/packages/compat/src/compat-adapters/ember-composable-helpers.ts @@ -3,7 +3,7 @@ import { join } from 'path'; import { Node } from 'broccoli-node-api'; import { readdirSync, writeFileSync, readFileSync } from 'fs'; import { pathExistsSync, removeSync } from 'fs-extra'; -import Funnel from 'broccoli-funnel'; +import { Funnel } from 'broccoli-funnel'; import { transform } from '@babel/core'; import { stripBadReexportsPlugin } from '../compat-utils'; diff --git a/packages/compat/src/compat-adapters/ember-source.ts b/packages/compat/src/compat-adapters/ember-source.ts index d5a358d6f..87a079149 100644 --- a/packages/compat/src/compat-adapters/ember-source.ts +++ b/packages/compat/src/compat-adapters/ember-source.ts @@ -1,5 +1,5 @@ import V1Addon from '../v1-addon'; -import Funnel from 'broccoli-funnel'; +import { Funnel } from 'broccoli-funnel'; import mergeTrees from 'broccoli-merge-trees'; import AddToTree from '../add-to-tree'; import { outputFileSync, unlinkSync } from 'fs-extra'; diff --git a/packages/compat/src/modules-compat.ts b/packages/compat/src/modules-compat.ts index ffe2e247d..693db4f51 100644 --- a/packages/compat/src/modules-compat.ts +++ b/packages/compat/src/modules-compat.ts @@ -1,4 +1,4 @@ -import Funnel from 'broccoli-funnel'; +import { Funnel } from 'broccoli-funnel'; import { Node } from 'broccoli-node-api'; import mergeTrees from 'broccoli-merge-trees'; diff --git a/packages/compat/src/observe-tree.ts b/packages/compat/src/observe-tree.ts index 1740f66fb..e60c836c6 100644 --- a/packages/compat/src/observe-tree.ts +++ b/packages/compat/src/observe-tree.ts @@ -1,5 +1,5 @@ import { Node } from 'broccoli-node-api'; -import Funnel from 'broccoli-funnel'; +import { Funnel } from 'broccoli-funnel'; export default class ObserveTree extends Funnel { constructor(combinedVendor: Node, private hook: (outputPath: string) => Promise | void) { diff --git a/packages/compat/src/rewrite-addon-tree.ts b/packages/compat/src/rewrite-addon-tree.ts index c4268c6a4..c529406fb 100644 --- a/packages/compat/src/rewrite-addon-tree.ts +++ b/packages/compat/src/rewrite-addon-tree.ts @@ -1,4 +1,4 @@ -import Funnel from 'broccoli-funnel'; +import { Funnel } from 'broccoli-funnel'; import mergeTrees from 'broccoli-merge-trees'; import Snitch from './snitch'; import { Node } from 'broccoli-node-api'; diff --git a/packages/compat/src/snitch.ts b/packages/compat/src/snitch.ts index 9b137a94a..1c8202e20 100644 --- a/packages/compat/src/snitch.ts +++ b/packages/compat/src/snitch.ts @@ -1,4 +1,4 @@ -import Funnel, { Options as FunnelOptions } from 'broccoli-funnel'; +import { Funnel, Options as FunnelOptions } from 'broccoli-funnel'; import walkSync from 'walk-sync'; import { Node } from 'broccoli-node-api'; diff --git a/packages/compat/src/v1-addon.ts b/packages/compat/src/v1-addon.ts index 37c9d8a7e..1f081266d 100644 --- a/packages/compat/src/v1-addon.ts +++ b/packages/compat/src/v1-addon.ts @@ -2,7 +2,7 @@ import { Memoize } from 'typescript-memoize'; import { dirname, isAbsolute, join, relative } from 'path'; import { sync as pkgUpSync } from 'pkg-up'; import { existsSync, pathExistsSync } from 'fs-extra'; -import Funnel, { Options as FunnelOptions } from 'broccoli-funnel'; +import { Funnel, Options as FunnelOptions } from 'broccoli-funnel'; import { UnwatchedDir, WatchedDir } from 'broccoli-source'; import RewritePackageJSON from './rewrite-package-json'; import { todo, unsupported } from '@embroider/core/src/messages'; diff --git a/packages/compat/src/v1-app.ts b/packages/compat/src/v1-app.ts index 74005622d..173c92ed4 100644 --- a/packages/compat/src/v1-app.ts +++ b/packages/compat/src/v1-app.ts @@ -1,7 +1,7 @@ import { Memoize } from 'typescript-memoize'; import { sync as pkgUpSync } from 'pkg-up'; import { join, dirname } from 'path'; -import Funnel from 'broccoli-funnel'; +import { Funnel } from 'broccoli-funnel'; import mergeTrees from 'broccoli-merge-trees'; import { WatchedDir } from 'broccoli-source'; import resolve from 'resolve'; diff --git a/packages/util/package.json b/packages/util/package.json index ef096e268..daaf37687 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -29,7 +29,7 @@ }, "dependencies": { "@embroider/macros": "0.37.0", - "broccoli-funnel": "^2.0.1", + "broccoli-funnel": "ef4/broccoli-funnel#d133c15aa7dd408222b544346ecf76a24c170af1", "ember-cli-babel": "^7.23.1" }, "devDependencies": { diff --git a/packages/util/shim.ts b/packages/util/shim.ts index 26ae52c75..69b6a5e98 100644 --- a/packages/util/shim.ts +++ b/packages/util/shim.ts @@ -5,7 +5,7 @@ import { AddonInstance, isDeepAddonInstance, } from '@embroider/shared-internals'; -import Funnel from 'broccoli-funnel'; +import { Funnel } from 'broccoli-funnel'; import type { Node } from 'broccoli-node-api'; const MIN_SUPPORT_LEVEL = 1; diff --git a/test-packages/funky-sample-addon/package.json b/test-packages/funky-sample-addon/package.json index a45b7a296..91e6f1350 100644 --- a/test-packages/funky-sample-addon/package.json +++ b/test-packages/funky-sample-addon/package.json @@ -21,7 +21,7 @@ "dependencies": { "@embroider/macros": "0.37.0", "broccoli-babel-transpiler": "^5.5.0", - "broccoli-funnel": "^2.0.2", + "broccoli-funnel": "ef4/broccoli-funnel#d133c15aa7dd408222b544346ecf76a24c170af1", "broccoli-merge-trees": "^3.0.2", "ember-cli-babel": "^7.20.5", "ember-cli-htmlbars": "^4.3.1" diff --git a/types/broccoli-funnel/index.d.ts b/types/broccoli-funnel/index.d.ts index 5e3f79955..820d5366b 100644 --- a/types/broccoli-funnel/index.d.ts +++ b/types/broccoli-funnel/index.d.ts @@ -11,9 +11,12 @@ declare module 'broccoli-funnel' { getDestinationPath?: (relativePath: string) => string; annotation?: string; } - export default class Funnel extends Plugin { + + export class Funnel extends Plugin { constructor(inputTree: BroccoliNode, options: Options); build(): Promise; protected srcDir: string; } + + export default function (inputTree: BroccoliNode, options: Options): Funnel; } diff --git a/yarn.lock b/yarn.lock index c2388e9f9..45ecb9051 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4521,6 +4521,21 @@ broccoli-funnel@^3.0.3: path-posix "^1.0.0" walk-sync "^2.0.2" +broccoli-funnel@ef4/broccoli-funnel#d133c15aa7dd408222b544346ecf76a24c170af1: + version "3.0.3" + resolved "https://codeload.github.com/ef4/broccoli-funnel/tar.gz/d133c15aa7dd408222b544346ecf76a24c170af1" + dependencies: + array-equal "^1.0.0" + blank-object "^1.0.1" + broccoli-plugin "^4.0.1" + debug "^4.1.1" + fast-ordered-set "^1.0.0" + fs-tree-diff "^2.0.1" + heimdalljs "^0.2.0" + minimatch "^3.0.0" + path-posix "^1.0.0" + walk-sync "^2.0.2" + broccoli-kitchen-sink-helpers@^0.2.5: version "0.2.9" resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" @@ -17222,12 +17237,7 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript-memoize@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typescript-memoize/-/typescript-memoize-1.0.0.tgz#ad3b0e7e5a411ca234be123f913a2a31302b7eb6" - integrity sha512-B1eufjs/mGzHqoGeI1VT/dnSBoZr2v3i3/Wm8NmdxlZflyVdleE8wO0QwUuj4NfundD7T5nU3I7HSKp/5BD9og== - -typescript-memoize@^1.0.0-alpha.3: +typescript-memoize@^1.0.0, typescript-memoize@^1.0.0-alpha.3: version "1.0.0" resolved "https://registry.yarnpkg.com/typescript-memoize/-/typescript-memoize-1.0.0.tgz#ad3b0e7e5a411ca234be123f913a2a31302b7eb6" integrity sha512-B1eufjs/mGzHqoGeI1VT/dnSBoZr2v3i3/Wm8NmdxlZflyVdleE8wO0QwUuj4NfundD7T5nU3I7HSKp/5BD9og== From 258a5dcad8149a39e2512745ec575196e5ec5c0e Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Tue, 30 Mar 2021 14:02:38 -0400 Subject: [PATCH 12/14] Revert "upgrading broccoli-funnel" This reverts commit dad9d18938f4b2a4debd4624dec065485c26d056. This newer broccoli-funnel has too many bugs --- packages/compat/package.json | 2 +- packages/compat/src/add-to-tree.ts | 2 +- packages/compat/src/build-compat-addon.ts | 2 +- .../src/compat-adapters/ember-asset-loader.ts | 2 +- .../compat-adapters/ember-cli-clipboard.ts | 2 +- .../ember-cli-deprecation-workflow.ts | 2 +- .../src/compat-adapters/ember-cli-mirage.ts | 2 +- .../ember-composable-helpers.ts | 2 +- .../src/compat-adapters/ember-source.ts | 2 +- packages/compat/src/modules-compat.ts | 2 +- packages/compat/src/observe-tree.ts | 2 +- packages/compat/src/rewrite-addon-tree.ts | 2 +- packages/compat/src/snitch.ts | 2 +- packages/compat/src/v1-addon.ts | 2 +- packages/compat/src/v1-app.ts | 2 +- packages/util/package.json | 2 +- packages/util/shim.ts | 2 +- test-packages/funky-sample-addon/package.json | 2 +- types/broccoli-funnel/index.d.ts | 5 +---- yarn.lock | 22 +++++-------------- 20 files changed, 25 insertions(+), 38 deletions(-) diff --git a/packages/compat/package.json b/packages/compat/package.json index 74d5997a1..4e069231a 100644 --- a/packages/compat/package.json +++ b/packages/compat/package.json @@ -40,7 +40,7 @@ "broccoli": "^3.4.2", "broccoli-concat": "^3.7.3", "broccoli-file-creator": "^2.1.1", - "broccoli-funnel": "ef4/broccoli-funnel#d133c15aa7dd408222b544346ecf76a24c170af1", + "broccoli-funnel": "^2.0.1", "broccoli-merge-trees": "^3.0.0", "broccoli-persistent-filter": "^3.1.2", "broccoli-plugin": "^4.0.0", diff --git a/packages/compat/src/add-to-tree.ts b/packages/compat/src/add-to-tree.ts index 9fe1100e7..12e83a256 100644 --- a/packages/compat/src/add-to-tree.ts +++ b/packages/compat/src/add-to-tree.ts @@ -1,5 +1,5 @@ import { Node } from 'broccoli-node-api'; -import { Funnel } from 'broccoli-funnel'; +import Funnel from 'broccoli-funnel'; export default class AddToTree extends Funnel { constructor(combinedVendor: Node, private hook: (outputPath: string) => Promise | void) { diff --git a/packages/compat/src/build-compat-addon.ts b/packages/compat/src/build-compat-addon.ts index f11396749..96a7d5bfc 100644 --- a/packages/compat/src/build-compat-addon.ts +++ b/packages/compat/src/build-compat-addon.ts @@ -4,7 +4,7 @@ import SmooshPackageJSON from './smoosh-package-json'; import broccoliMergeTrees from 'broccoli-merge-trees'; import { Node } from 'broccoli-node-api'; import OneShot from './one-shot'; -import { Funnel } from 'broccoli-funnel'; +import Funnel from 'broccoli-funnel'; import { UnwatchedDir, WatchedDir } from 'broccoli-source'; import EmptyPackageTree from './empty-package-tree'; diff --git a/packages/compat/src/compat-adapters/ember-asset-loader.ts b/packages/compat/src/compat-adapters/ember-asset-loader.ts index 3ce173b15..884d81a9c 100644 --- a/packages/compat/src/compat-adapters/ember-asset-loader.ts +++ b/packages/compat/src/compat-adapters/ember-asset-loader.ts @@ -1,5 +1,5 @@ import V1Addon from '../v1-addon'; -import { Funnel } from 'broccoli-funnel'; +import Funnel from 'broccoli-funnel'; import cloneDeep from 'lodash/cloneDeep'; // ember-asset-loader's ManifestGenerator (which is used as the Addon base class diff --git a/packages/compat/src/compat-adapters/ember-cli-clipboard.ts b/packages/compat/src/compat-adapters/ember-cli-clipboard.ts index 571070df1..daee5abc3 100644 --- a/packages/compat/src/compat-adapters/ember-cli-clipboard.ts +++ b/packages/compat/src/compat-adapters/ember-cli-clipboard.ts @@ -1,6 +1,6 @@ import V1Addon from '../v1-addon'; import { Memoize } from 'typescript-memoize'; -import { Funnel } from 'broccoli-funnel'; +import Funnel from 'broccoli-funnel'; export default class EmberCLIClipboard extends V1Addon { @Memoize() diff --git a/packages/compat/src/compat-adapters/ember-cli-deprecation-workflow.ts b/packages/compat/src/compat-adapters/ember-cli-deprecation-workflow.ts index 6de8957fb..3332fdd1c 100644 --- a/packages/compat/src/compat-adapters/ember-cli-deprecation-workflow.ts +++ b/packages/compat/src/compat-adapters/ember-cli-deprecation-workflow.ts @@ -3,7 +3,7 @@ import { join, dirname } from 'path'; import { UnwatchedDir } from 'broccoli-source'; import resolve from 'resolve'; import { Memoize } from 'typescript-memoize'; -import { Funnel } from 'broccoli-funnel'; +import Funnel from 'broccoli-funnel'; export default class extends V1Addon { @Memoize() diff --git a/packages/compat/src/compat-adapters/ember-cli-mirage.ts b/packages/compat/src/compat-adapters/ember-cli-mirage.ts index 0328ac3ae..ba285eddf 100644 --- a/packages/compat/src/compat-adapters/ember-cli-mirage.ts +++ b/packages/compat/src/compat-adapters/ember-cli-mirage.ts @@ -1,5 +1,5 @@ import V1Addon from '../v1-addon'; -import { Funnel } from 'broccoli-funnel'; +import Funnel from 'broccoli-funnel'; import { AddonMeta } from '@embroider/core'; export default class extends V1Addon { diff --git a/packages/compat/src/compat-adapters/ember-composable-helpers.ts b/packages/compat/src/compat-adapters/ember-composable-helpers.ts index 215951baf..d8a52db74 100644 --- a/packages/compat/src/compat-adapters/ember-composable-helpers.ts +++ b/packages/compat/src/compat-adapters/ember-composable-helpers.ts @@ -3,7 +3,7 @@ import { join } from 'path'; import { Node } from 'broccoli-node-api'; import { readdirSync, writeFileSync, readFileSync } from 'fs'; import { pathExistsSync, removeSync } from 'fs-extra'; -import { Funnel } from 'broccoli-funnel'; +import Funnel from 'broccoli-funnel'; import { transform } from '@babel/core'; import { stripBadReexportsPlugin } from '../compat-utils'; diff --git a/packages/compat/src/compat-adapters/ember-source.ts b/packages/compat/src/compat-adapters/ember-source.ts index 87a079149..d5a358d6f 100644 --- a/packages/compat/src/compat-adapters/ember-source.ts +++ b/packages/compat/src/compat-adapters/ember-source.ts @@ -1,5 +1,5 @@ import V1Addon from '../v1-addon'; -import { Funnel } from 'broccoli-funnel'; +import Funnel from 'broccoli-funnel'; import mergeTrees from 'broccoli-merge-trees'; import AddToTree from '../add-to-tree'; import { outputFileSync, unlinkSync } from 'fs-extra'; diff --git a/packages/compat/src/modules-compat.ts b/packages/compat/src/modules-compat.ts index 693db4f51..ffe2e247d 100644 --- a/packages/compat/src/modules-compat.ts +++ b/packages/compat/src/modules-compat.ts @@ -1,4 +1,4 @@ -import { Funnel } from 'broccoli-funnel'; +import Funnel from 'broccoli-funnel'; import { Node } from 'broccoli-node-api'; import mergeTrees from 'broccoli-merge-trees'; diff --git a/packages/compat/src/observe-tree.ts b/packages/compat/src/observe-tree.ts index e60c836c6..1740f66fb 100644 --- a/packages/compat/src/observe-tree.ts +++ b/packages/compat/src/observe-tree.ts @@ -1,5 +1,5 @@ import { Node } from 'broccoli-node-api'; -import { Funnel } from 'broccoli-funnel'; +import Funnel from 'broccoli-funnel'; export default class ObserveTree extends Funnel { constructor(combinedVendor: Node, private hook: (outputPath: string) => Promise | void) { diff --git a/packages/compat/src/rewrite-addon-tree.ts b/packages/compat/src/rewrite-addon-tree.ts index c529406fb..c4268c6a4 100644 --- a/packages/compat/src/rewrite-addon-tree.ts +++ b/packages/compat/src/rewrite-addon-tree.ts @@ -1,4 +1,4 @@ -import { Funnel } from 'broccoli-funnel'; +import Funnel from 'broccoli-funnel'; import mergeTrees from 'broccoli-merge-trees'; import Snitch from './snitch'; import { Node } from 'broccoli-node-api'; diff --git a/packages/compat/src/snitch.ts b/packages/compat/src/snitch.ts index 1c8202e20..9b137a94a 100644 --- a/packages/compat/src/snitch.ts +++ b/packages/compat/src/snitch.ts @@ -1,4 +1,4 @@ -import { Funnel, Options as FunnelOptions } from 'broccoli-funnel'; +import Funnel, { Options as FunnelOptions } from 'broccoli-funnel'; import walkSync from 'walk-sync'; import { Node } from 'broccoli-node-api'; diff --git a/packages/compat/src/v1-addon.ts b/packages/compat/src/v1-addon.ts index 1f081266d..37c9d8a7e 100644 --- a/packages/compat/src/v1-addon.ts +++ b/packages/compat/src/v1-addon.ts @@ -2,7 +2,7 @@ import { Memoize } from 'typescript-memoize'; import { dirname, isAbsolute, join, relative } from 'path'; import { sync as pkgUpSync } from 'pkg-up'; import { existsSync, pathExistsSync } from 'fs-extra'; -import { Funnel, Options as FunnelOptions } from 'broccoli-funnel'; +import Funnel, { Options as FunnelOptions } from 'broccoli-funnel'; import { UnwatchedDir, WatchedDir } from 'broccoli-source'; import RewritePackageJSON from './rewrite-package-json'; import { todo, unsupported } from '@embroider/core/src/messages'; diff --git a/packages/compat/src/v1-app.ts b/packages/compat/src/v1-app.ts index 173c92ed4..74005622d 100644 --- a/packages/compat/src/v1-app.ts +++ b/packages/compat/src/v1-app.ts @@ -1,7 +1,7 @@ import { Memoize } from 'typescript-memoize'; import { sync as pkgUpSync } from 'pkg-up'; import { join, dirname } from 'path'; -import { Funnel } from 'broccoli-funnel'; +import Funnel from 'broccoli-funnel'; import mergeTrees from 'broccoli-merge-trees'; import { WatchedDir } from 'broccoli-source'; import resolve from 'resolve'; diff --git a/packages/util/package.json b/packages/util/package.json index daaf37687..ef096e268 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -29,7 +29,7 @@ }, "dependencies": { "@embroider/macros": "0.37.0", - "broccoli-funnel": "ef4/broccoli-funnel#d133c15aa7dd408222b544346ecf76a24c170af1", + "broccoli-funnel": "^2.0.1", "ember-cli-babel": "^7.23.1" }, "devDependencies": { diff --git a/packages/util/shim.ts b/packages/util/shim.ts index 69b6a5e98..26ae52c75 100644 --- a/packages/util/shim.ts +++ b/packages/util/shim.ts @@ -5,7 +5,7 @@ import { AddonInstance, isDeepAddonInstance, } from '@embroider/shared-internals'; -import { Funnel } from 'broccoli-funnel'; +import Funnel from 'broccoli-funnel'; import type { Node } from 'broccoli-node-api'; const MIN_SUPPORT_LEVEL = 1; diff --git a/test-packages/funky-sample-addon/package.json b/test-packages/funky-sample-addon/package.json index 91e6f1350..a45b7a296 100644 --- a/test-packages/funky-sample-addon/package.json +++ b/test-packages/funky-sample-addon/package.json @@ -21,7 +21,7 @@ "dependencies": { "@embroider/macros": "0.37.0", "broccoli-babel-transpiler": "^5.5.0", - "broccoli-funnel": "ef4/broccoli-funnel#d133c15aa7dd408222b544346ecf76a24c170af1", + "broccoli-funnel": "^2.0.2", "broccoli-merge-trees": "^3.0.2", "ember-cli-babel": "^7.20.5", "ember-cli-htmlbars": "^4.3.1" diff --git a/types/broccoli-funnel/index.d.ts b/types/broccoli-funnel/index.d.ts index 820d5366b..5e3f79955 100644 --- a/types/broccoli-funnel/index.d.ts +++ b/types/broccoli-funnel/index.d.ts @@ -11,12 +11,9 @@ declare module 'broccoli-funnel' { getDestinationPath?: (relativePath: string) => string; annotation?: string; } - - export class Funnel extends Plugin { + export default class Funnel extends Plugin { constructor(inputTree: BroccoliNode, options: Options); build(): Promise; protected srcDir: string; } - - export default function (inputTree: BroccoliNode, options: Options): Funnel; } diff --git a/yarn.lock b/yarn.lock index 45ecb9051..c2388e9f9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4521,21 +4521,6 @@ broccoli-funnel@^3.0.3: path-posix "^1.0.0" walk-sync "^2.0.2" -broccoli-funnel@ef4/broccoli-funnel#d133c15aa7dd408222b544346ecf76a24c170af1: - version "3.0.3" - resolved "https://codeload.github.com/ef4/broccoli-funnel/tar.gz/d133c15aa7dd408222b544346ecf76a24c170af1" - dependencies: - array-equal "^1.0.0" - blank-object "^1.0.1" - broccoli-plugin "^4.0.1" - debug "^4.1.1" - fast-ordered-set "^1.0.0" - fs-tree-diff "^2.0.1" - heimdalljs "^0.2.0" - minimatch "^3.0.0" - path-posix "^1.0.0" - walk-sync "^2.0.2" - broccoli-kitchen-sink-helpers@^0.2.5: version "0.2.9" resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" @@ -17237,7 +17222,12 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript-memoize@^1.0.0, typescript-memoize@^1.0.0-alpha.3: +typescript-memoize@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typescript-memoize/-/typescript-memoize-1.0.0.tgz#ad3b0e7e5a411ca234be123f913a2a31302b7eb6" + integrity sha512-B1eufjs/mGzHqoGeI1VT/dnSBoZr2v3i3/Wm8NmdxlZflyVdleE8wO0QwUuj4NfundD7T5nU3I7HSKp/5BD9og== + +typescript-memoize@^1.0.0-alpha.3: version "1.0.0" resolved "https://registry.yarnpkg.com/typescript-memoize/-/typescript-memoize-1.0.0.tgz#ad3b0e7e5a411ca234be123f913a2a31302b7eb6" integrity sha512-B1eufjs/mGzHqoGeI1VT/dnSBoZr2v3i3/Wm8NmdxlZflyVdleE8wO0QwUuj4NfundD7T5nU3I7HSKp/5BD9og== From ffcd4f0b538bfe9cf9d2dbdc64f568d0173dae6d Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Tue, 30 Mar 2021 14:05:30 -0400 Subject: [PATCH 13/14] switching to a 2.0 broccoli-funnel fork bc 3.0 is too rough --- packages/compat/package.json | 2 +- packages/util/package.json | 2 +- test-packages/funky-sample-addon/package.json | 2 +- yarn.lock | 25 ++++++++++++++----- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/packages/compat/package.json b/packages/compat/package.json index 4e069231a..acbd33ad0 100644 --- a/packages/compat/package.json +++ b/packages/compat/package.json @@ -40,7 +40,7 @@ "broccoli": "^3.4.2", "broccoli-concat": "^3.7.3", "broccoli-file-creator": "^2.1.1", - "broccoli-funnel": "^2.0.1", + "broccoli-funnel": "ef4/broccoli-funnel#c70d060076e14793e8495571f304a976afc754ac", "broccoli-merge-trees": "^3.0.0", "broccoli-persistent-filter": "^3.1.2", "broccoli-plugin": "^4.0.0", diff --git a/packages/util/package.json b/packages/util/package.json index ef096e268..ced4ee66c 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -29,7 +29,7 @@ }, "dependencies": { "@embroider/macros": "0.37.0", - "broccoli-funnel": "^2.0.1", + "broccoli-funnel": "ef4/broccoli-funnel#c70d060076e14793e8495571f304a976afc754ac", "ember-cli-babel": "^7.23.1" }, "devDependencies": { diff --git a/test-packages/funky-sample-addon/package.json b/test-packages/funky-sample-addon/package.json index a45b7a296..58d5aa699 100644 --- a/test-packages/funky-sample-addon/package.json +++ b/test-packages/funky-sample-addon/package.json @@ -21,7 +21,7 @@ "dependencies": { "@embroider/macros": "0.37.0", "broccoli-babel-transpiler": "^5.5.0", - "broccoli-funnel": "^2.0.2", + "broccoli-funnel": "ef4/broccoli-funnel#c70d060076e14793e8495571f304a976afc754ac", "broccoli-merge-trees": "^3.0.2", "ember-cli-babel": "^7.20.5", "ember-cli-htmlbars": "^4.3.1" diff --git a/yarn.lock b/yarn.lock index c2388e9f9..537f4ef64 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4521,6 +4521,24 @@ broccoli-funnel@^3.0.3: path-posix "^1.0.0" walk-sync "^2.0.2" +broccoli-funnel@ef4/broccoli-funnel#c70d060076e14793e8495571f304a976afc754ac: + version "2.0.2-ef4.0" + resolved "https://codeload.github.com/ef4/broccoli-funnel/tar.gz/c70d060076e14793e8495571f304a976afc754ac" + dependencies: + array-equal "^1.0.0" + blank-object "^1.0.1" + broccoli-plugin "^1.3.0" + debug "^2.2.0" + fast-ordered-set "^1.0.0" + fs-tree-diff "^0.5.3" + heimdalljs "^0.2.0" + minimatch "^3.0.0" + mkdirp "^0.5.0" + path-posix "^1.0.0" + rimraf "^2.4.3" + symlink-or-copy "^1.0.0" + walk-sync "^2.2.0" + broccoli-kitchen-sink-helpers@^0.2.5: version "0.2.9" resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" @@ -17222,12 +17240,7 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript-memoize@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typescript-memoize/-/typescript-memoize-1.0.0.tgz#ad3b0e7e5a411ca234be123f913a2a31302b7eb6" - integrity sha512-B1eufjs/mGzHqoGeI1VT/dnSBoZr2v3i3/Wm8NmdxlZflyVdleE8wO0QwUuj4NfundD7T5nU3I7HSKp/5BD9og== - -typescript-memoize@^1.0.0-alpha.3: +typescript-memoize@^1.0.0, typescript-memoize@^1.0.0-alpha.3: version "1.0.0" resolved "https://registry.yarnpkg.com/typescript-memoize/-/typescript-memoize-1.0.0.tgz#ad3b0e7e5a411ca234be123f913a2a31302b7eb6" integrity sha512-B1eufjs/mGzHqoGeI1VT/dnSBoZr2v3i3/Wm8NmdxlZflyVdleE8wO0QwUuj4NfundD7T5nU3I7HSKp/5BD9og== From 451f780733a21c2b6d24825b09293f99c2e0009a Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Tue, 30 Mar 2021 16:18:14 -0400 Subject: [PATCH 14/14] allow well-defined import adjustments in native v2 packages --- .../core/src/babel-plugin-adjust-imports.ts | 23 +++++++++++++++- packages/shared-internals/package.json | 1 + .../src/ember-standard-modules.ts | 27 +++++++++++++++++++ packages/shared-internals/src/index.ts | 1 + 4 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 packages/shared-internals/src/ember-standard-modules.ts diff --git a/packages/core/src/babel-plugin-adjust-imports.ts b/packages/core/src/babel-plugin-adjust-imports.ts index 7633165c1..e3f487c9f 100644 --- a/packages/core/src/babel-plugin-adjust-imports.ts +++ b/packages/core/src/babel-plugin-adjust-imports.ts @@ -1,4 +1,4 @@ -import { packageName as getPackageName } from '@embroider/shared-internals'; +import { emberVirtualPackages, emberVirtualPeerDeps, packageName as getPackageName } from '@embroider/shared-internals'; import { join, dirname, resolve } from 'path'; import { NodePath } from '@babel/traverse'; import type * as t from '@babel/types'; @@ -279,6 +279,27 @@ function handleExternal(specifier: string, sourceFile: AdjustFile, opts: Options return makeExternal(specifier, sourceFile, opts); } + if (pkg.isV2Ember()) { + // native v2 packages don't automatically externalize *everything* the way + // auto-upgraded packages do, but they still externalize known and approved + // ember virtual packages (like @ember/component) + if (emberVirtualPackages.has(packageName)) { + return makeExternal(specifier, sourceFile, opts); + } + + // native v2 packages don't automatically get to use every other addon as a + // peerDep, but they do get the known and approved ember virtual peer deps, + // like @glimmer/component + if (emberVirtualPeerDeps.has(packageName)) { + if (!opts.activeAddons[packageName]) { + throw new Error( + `${pkg.name} is trying to import from ${packageName}, which is supposed to be present in all ember apps but seems to be missing` + ); + } + return explicitRelative(dirname(sourceFile.name), specifier.replace(packageName, opts.activeAddons[packageName])); + } + } + // non-resolvable imports in dynamic positions become runtime errors, not // build-time errors, so we emit the runtime error module here before the // stage3 packager has a chance to see the missing module. (Maybe some stage3 diff --git a/packages/shared-internals/package.json b/packages/shared-internals/package.json index ee679679e..db4013785 100644 --- a/packages/shared-internals/package.json +++ b/packages/shared-internals/package.json @@ -27,6 +27,7 @@ "test": "jest" }, "dependencies": { + "ember-rfc176-data": "^0.3.17", "resolve-package-path": "^1.2.2", "pkg-up": "^3.1.0", "typescript-memoize": "^1.0.0-alpha.3", diff --git a/packages/shared-internals/src/ember-standard-modules.ts b/packages/shared-internals/src/ember-standard-modules.ts new file mode 100644 index 000000000..ea1e9de1e --- /dev/null +++ b/packages/shared-internals/src/ember-standard-modules.ts @@ -0,0 +1,27 @@ +// I'm doing this as a json import because even though that's not standard JS, +// it's relaively easy to consume into builds for the web. As opposed to doing +// something like fs.readFile, which is harder. +// +// @ts-ignore +import mappings from 'ember-rfc176-data/mappings.json'; + +// these are packages that available to import in standard ember code that don't +// exist as real packages. If a build system encounters them in stage 3, it +// should convert them to runtime AMD require. +// +// Some of them (like @embroider/macros) won't ever be seen in stage 3, because +// earlier plugins should take care of them. +// +// In embroider builds using ember-source >= 3.28, you won't see *any* of these +// in stage3 because ember-source uses the standard rename-modules feature to +// map them into real modules within ember-source. +export const emberVirtualPackages = new Set(mappings.map((m: any) => m.module)); + +// these are *real* packages that every ember addon is allow to resolve *as if +// they were peerDepenedencies, because the host application promises to have +// these packages. In principle, we could force every addon to declare these as +// real peerDeps all the way down the dependency graph, but in practice that +// 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']); diff --git a/packages/shared-internals/src/index.ts b/packages/shared-internals/src/index.ts index 2ea36ce9f..f64dadec3 100644 --- a/packages/shared-internals/src/index.ts +++ b/packages/shared-internals/src/index.ts @@ -6,3 +6,4 @@ export { default as PackageCache } from './package-cache'; export { default as babelFilter } from './babel-filter'; export { default as packageName } from './package-name'; export * from './ember-cli-models'; +export * from './ember-standard-modules';