diff --git a/.eslintrc.js b/.eslintrc.js index 1afb795562b..5c1c4b58cb9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -50,7 +50,7 @@ module.exports = { '@typescript-eslint/ban-types': 'off', '@typescript-eslint/no-empty-function': 'off', '@typescript-eslint/no-this-alias': 'off', - '@typescript-eslint/no-var-requires': 'warn', + '@typescript-eslint/no-var-requires': 'off', // TODO: Enable and fix these rules // Typescript provides better types with these rules enabled @@ -81,6 +81,8 @@ module.exports = { Set: true, Symbol: true, WeakMap: true, + require: true, + define: true, }, rules: { diff --git a/broccoli/packages.js b/broccoli/packages.js index db25d4d7712..ab8f37c035f 100644 --- a/broccoli/packages.js +++ b/broccoli/packages.js @@ -5,7 +5,6 @@ const path = require('path'); const Rollup = require('broccoli-rollup'); const Funnel = require('broccoli-funnel'); const MergeTrees = require('broccoli-merge-trees'); -const Babel = require('broccoli-babel-transpiler'); const typescript = require('broccoli-typescript-compiler').default; const BroccoliDebug = require('broccoli-debug'); const findLib = require('./find-lib'); @@ -18,7 +17,6 @@ const StringReplace = require('broccoli-string-replace'); const GlimmerTemplatePrecompiler = require('./glimmer-template-compiler'); const VERSION_PLACEHOLDER = /VERSION_STRING_PLACEHOLDER/g; const canaryFeatures = require('./canary-features'); -const injectNodeGlobals = require('./transforms/inject-node-globals'); const debugTree = BroccoliDebug.buildDebugCallback('ember-source'); @@ -44,7 +42,7 @@ module.exports.jquery = function _jquery() { }); }; -module.exports.internalLoader = function _internalLoader() { +module.exports.loader = function _loader() { return new Funnel('packages/loader/lib', { files: ['index.js'], getDestinationPath() { @@ -234,6 +232,7 @@ function glimmerTrees(entries) { let trees = []; let queue = Array.isArray(entries) ? entries.slice() : [entries]; let name; + while ((name = queue.pop()) !== undefined) { if (seen.has(name)) { continue; @@ -255,14 +254,8 @@ function glimmerTrees(entries) { queue.push(...dependencies); } } - return new Babel(new MergeTrees(trees), { - sourceMaps: true, - plugins: [ - // ensures `@glimmer/compiler` requiring `crypto` works properly - // in both browser and node-land - injectNodeGlobals, - ], - }); + + return new MergeTrees(trees); } module.exports.glimmerCompilerES = () => { diff --git a/broccoli/transforms/inject-node-globals.js b/broccoli/transforms/inject-node-globals.js deleted file mode 100644 index b5bba89fc1e..00000000000 --- a/broccoli/transforms/inject-node-globals.js +++ /dev/null @@ -1,52 +0,0 @@ -function injectNodeGlobals({ types: t }) { - let requireId; - let importDecl; - let moduleId; - return { - name: 'inject require', - visitor: { - Program: { - enter(path, state) { - if (state.file.opts.filename.match(/node-module\/index.js/)) return; - - requireId = path.scope.globals.require; - moduleId = path.scope.globals.module; - - if (requireId || moduleId) { - let specifiers = []; - let source = t.stringLiteral('node-module'); - - if (requireId) { - delete path.scope.globals.require; - specifiers.push(t.importSpecifier(requireId, t.identifier('require'))); - } - - if (moduleId) { - delete path.scope.globals.module; - specifiers.push(t.importSpecifier(moduleId, t.identifier('module'))); - } - - importDecl = t.importDeclaration(specifiers, source); - path.unshiftContainer('body', importDecl); - } - }, - exit(path) { - if (requireId) { - path.scope.rename('require'); - } - }, - }, - ImportDeclaration(path) { - if (path.node === importDecl) { - path.scope.registerDeclaration(path); - } - }, - }, - }; -} - -injectNodeGlobals.baseDir = function () { - return 'babel-plugin-transform-es2015-modules-amd'; -}; - -module.exports = injectNodeGlobals; diff --git a/ember-cli-build.js b/ember-cli-build.js index 8c0254be9bc..77b3aa5c9e3 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -15,7 +15,7 @@ Error.stackTraceLimit = Infinity; const { routerES, jquery, - internalLoader, + loader, qunit, handlebarsES, rsvpES, @@ -246,7 +246,14 @@ function templateCompilerBundle(emberPackages, transpileTree) { } function testHarness() { - return new MergeTrees([emptyTestem(), testPolyfills(), testIndexHTML(), qunit(), jquery()]); + return new MergeTrees([ + emptyTestem(), + testPolyfills(), + testIndexHTML(), + loader(), + qunit(), + jquery(), + ]); } function emptyTestem() { @@ -262,5 +269,5 @@ function templateCompilerDependencies() { } function emberHeaderFiles() { - return new MergeTrees([emberLicense(), internalLoader()]); + return new MergeTrees([emberLicense(), loader()]); } diff --git a/lib/index.js b/lib/index.js index 3af916860e7..0f9996d18e3 100644 --- a/lib/index.js +++ b/lib/index.js @@ -237,18 +237,11 @@ module.exports = { return new MergeTrees([ concatBundle(emberFiles, { outputFile: 'ember.js', - footer: "require('ember');", + footer: "require('@ember/-internals/bootstrap');", }), concatBundle(emberTestingFiles, { outputFile: 'ember-testing.js', - footer: ` - var testing = require('ember-testing'); - Ember.Test = testing.Test; - Ember.Test.Adapter = testing.Adapter; - Ember.Test.QUnitAdapter = testing.QUnitAdapter; - Ember.setupForTesting = testing.setupForTesting; - `, }), ]); }, diff --git a/packages/@ember/-internals/bootstrap/index.js b/packages/@ember/-internals/bootstrap/index.js new file mode 100644 index 00000000000..1248aa50f43 --- /dev/null +++ b/packages/@ember/-internals/bootstrap/index.js @@ -0,0 +1,30 @@ +import { context } from '@ember/-internals/environment'; + +(function () { + let Ember; + + function defineEmber(key) { + Object.defineProperty(context.exports, key, { + enumerable: true, + configurable: true, + get() { + if (!Ember) { + Ember = require('ember').default; + } + + return Ember; + }, + }); + } + + // Bootstrap the global + defineEmber('Ember'); + defineEmber('Em'); + + // Bootstrap Node module + // eslint-disable-next-line no-undef + if (typeof module === 'object' && typeof module.require === 'function') { + // eslint-disable-next-line no-undef + module.exports = Ember = require('ember').default; + } +})(); diff --git a/packages/@ember/-internals/environment/lib/global.ts b/packages/@ember/-internals/environment/lib/global.ts index ceaff0c112c..99cbbd76dc0 100644 --- a/packages/@ember/-internals/environment/lib/global.ts +++ b/packages/@ember/-internals/environment/lib/global.ts @@ -1,4 +1,4 @@ -/* globals global, window, self, mainContext */ +/* globals global, window, self */ declare const mainContext: object | undefined; // from lodash to catch fake globals diff --git a/packages/ember-template-compiler/index.ts b/packages/ember-template-compiler/index.ts index 3cdea8978d9..2239d71adfd 100644 --- a/packages/ember-template-compiler/index.ts +++ b/packages/ember-template-compiler/index.ts @@ -1,24 +1,27 @@ -import { context, ENV } from '@ember/-internals/environment'; +import { ENV } from '@ember/-internals/environment'; import { FEATURES } from '@ember/canary-features'; import VERSION from 'ember/version'; -export const _Ember = - (typeof (context.imports as any).Ember === 'object' && (context.imports as any).Ember) || {}; +declare global { + interface NodeRequire { + has(name: string): boolean; + } -// private API used by ember-cli-htmlbars to setup ENV and FEATURES -if (!_Ember.ENV) { - _Ember.ENV = ENV; -} -if (!_Ember.FEATURES) { - _Ember.FEATURES = FEATURES; -} -if (!_Ember.VERSION) { - _Ember.VERSION = VERSION; + function define(path: string, deps: string[], module: () => void): void; } -// used for adding Ember.Handlebars.compile for backwards compat -import setupGlobal from './lib/compat'; -setupGlobal(_Ember); +export let _Ember: unknown; + +try { + // tslint:disable-next-line: no-require-imports + _Ember = require('ember'); +} catch (e) { + _Ember = { + ENV, + FEATURES, + VERSION, + }; +} export { default as precompile } from './lib/system/precompile'; export { default as compile } from './lib/system/compile'; diff --git a/packages/ember-template-compiler/lib/system/compile.ts b/packages/ember-template-compiler/lib/system/compile.ts index 02a693e8faf..1061d0508e8 100644 --- a/packages/ember-template-compiler/lib/system/compile.ts +++ b/packages/ember-template-compiler/lib/system/compile.ts @@ -1,7 +1,6 @@ /** @module ember */ -import require, { has } from 'require'; import { EmberPrecompileOptions } from '../types'; import precompile from './precompile'; @@ -23,7 +22,7 @@ export default function compile( templateString: string, options: Partial = {} ): Factory { - if (!template && has('@ember/-internals/glimmer')) { + if (!template && require.has('@ember/-internals/glimmer')) { // tslint:disable-next-line:no-require-imports template = require('@ember/-internals/glimmer').template; } diff --git a/packages/ember-template-compiler/lib/system/initializer.ts b/packages/ember-template-compiler/lib/system/initializer.ts index 7a20796855c..80a8a0bb9e6 100644 --- a/packages/ember-template-compiler/lib/system/initializer.ts +++ b/packages/ember-template-compiler/lib/system/initializer.ts @@ -1,11 +1,10 @@ -import require, { has } from 'require'; import bootstrap from './bootstrap'; // Globals mode template compiler if ( - has('@ember/application') && - has('@ember/-internals/browser-environment') && - has('@ember/-internals/glimmer') + require.has('@ember/application') && + require.has('@ember/-internals/browser-environment') && + require.has('@ember/-internals/glimmer') ) { // tslint:disable:no-require-imports let emberEnv = require('@ember/-internals/browser-environment'); diff --git a/packages/ember/index.d.ts b/packages/ember/index.d.ts new file mode 100644 index 00000000000..32cfea9c4bf --- /dev/null +++ b/packages/ember/index.d.ts @@ -0,0 +1,5 @@ +declare module 'ember' { + declare const Ember: any; + + export default Ember; +} diff --git a/packages/ember/index.js b/packages/ember/index.js index 4c7ff4c1262..221238e4238 100644 --- a/packages/ember/index.js +++ b/packages/ember/index.js @@ -1,7 +1,4 @@ -import require, { has } from 'require'; - -import { getENV, getLookup, setLookup, ENV, context } from '@ember/-internals/environment'; -import { IS_NODE, module } from 'node-module'; +import { getENV, getLookup, setLookup, ENV } from '@ember/-internals/environment'; import * as utils from '@ember/-internals/utils'; import { Registry, Container } from '@ember/-internals/container'; import * as instrumentation from '@ember/instrumentation'; @@ -168,7 +165,7 @@ import { // ****@ember/-internals/environment**** -const Ember = (typeof context.imports.Ember === 'object' && context.imports.Ember) || {}; +const Ember = {}; import { isIE } from '@ember/-internals/browser-environment'; @@ -782,13 +779,27 @@ runLoadHooks('Ember.Application', Application); Ember.DataAdapter = extensionSupport.DataAdapter; Ember.ContainerDebugAdapter = extensionSupport.ContainerDebugAdapter; -if (has('ember-template-compiler')) { - require('ember-template-compiler'); +if (require.has('ember-template-compiler')) { + let templateCompiler = require('ember-template-compiler'); + + let EmberHandlebars = Ember.Handlebars; + if (!EmberHandlebars) { + Ember.Handlebars = EmberHandlebars = {}; + } + + let EmberHTMLBars = Ember.HTMLBars; + if (!EmberHTMLBars) { + Ember.HTMLBars = EmberHTMLBars = {}; + } + + EmberHTMLBars.precompile = EmberHandlebars.precompile = templateCompiler.precompile; + EmberHTMLBars.compile = EmberHandlebars.compile = templateCompiler.compile; + EmberHTMLBars.registerPlugin = templateCompiler.registerPlugin; } // do this to ensure that Ember.Test is defined properly on the global // if it is present. -if (has('ember-testing')) { +if (require.has('ember-testing')) { let testing = require('ember-testing'); Ember.Test = testing.Test; @@ -799,13 +810,13 @@ if (has('ember-testing')) { runLoadHooks('Ember'); -export default Ember; +Ember.__loader = { + require, + define, + registry: require._eak_seen, +}; -if (IS_NODE) { - module.exports = Ember; -} else { - context.exports.Ember = context.exports.Em = Ember; -} +export default Ember; /** @module jquery diff --git a/packages/ember/tests/reexports_test.js b/packages/ember/tests/reexports_test.js index 6c6562769b2..2b920689737 100644 --- a/packages/ember/tests/reexports_test.js +++ b/packages/ember/tests/reexports_test.js @@ -1,5 +1,4 @@ import Ember from '../index'; -import require from 'require'; import { FEATURES, EMBER_GLIMMER_HELPER_MANAGER, diff --git a/packages/internal-test-helpers/lib/confirm-export.js b/packages/internal-test-helpers/lib/confirm-export.js index 2f0be668fd4..2e81cb06b8e 100644 --- a/packages/internal-test-helpers/lib/confirm-export.js +++ b/packages/internal-test-helpers/lib/confirm-export.js @@ -1,5 +1,3 @@ -import require from 'require'; - function getDescriptor(obj, path) { let parts = path.split('.'); let value = obj; diff --git a/packages/internal-test-helpers/lib/ember-dev/setup-qunit.ts b/packages/internal-test-helpers/lib/ember-dev/setup-qunit.ts index bcc6c785ab7..5142e42d09d 100644 --- a/packages/internal-test-helpers/lib/ember-dev/setup-qunit.ts +++ b/packages/internal-test-helpers/lib/ember-dev/setup-qunit.ts @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import { getDebugFunction, setDebugFunction } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; diff --git a/packages/loader/lib/index.js b/packages/loader/lib/index.js index dcb6c7c4594..c811cf08800 100644 --- a/packages/loader/lib/index.js +++ b/packages/loader/lib/index.js @@ -1,12 +1,31 @@ -/*globals process */ -let define, require, Ember; - -// Used in @ember/-internals/environment/lib/global.js -mainContext = this; // eslint-disable-line no-undef +/* globals global globalThis self */ +let define, require; (function () { - let registry; - let seen; + let globalObj = + typeof globalThis !== 'undefined' + ? globalThis + : typeof self !== 'undefined' + ? self + : typeof window !== 'undefined' + ? window + : typeof global !== 'undefined' + ? global + : null; + + if (globalObj === null) { + throw new Error('unable to locate global object'); + } + + if (typeof globalObj.define === 'function' && typeof globalObj.require === 'function') { + define = globalObj.define; + require = globalObj.require; + + return; + } + + let registry = Object.create(null); + let seen = Object.create(null); function missingModule(name, referrerName) { if (referrerName) { @@ -47,7 +66,7 @@ mainContext = this; // eslint-disable-line no-undef } else if (deps[i] === 'require') { reified[i] = require; } else { - reified[i] = internalRequire(deps[i], name); + reified[i] = require(deps[i], name); } } @@ -56,57 +75,31 @@ mainContext = this; // eslint-disable-line no-undef return exports; } - let isNode = - typeof window === 'undefined' && - typeof process !== 'undefined' && - {}.toString.call(process) === '[object process]'; - - if (!isNode) { - Ember = this.Ember = this.Ember || {}; - } - - if (typeof Ember === 'undefined') { - Ember = {}; - } - - if (typeof Ember.__loader === 'undefined') { - registry = Object.create(null); - seen = Object.create(null); - - define = function (name, deps, callback) { - let value = {}; + require = function (name) { + return internalRequire(name, null); + }; - if (!callback) { - value.deps = []; - value.callback = deps; - } else { - value.deps = deps; - value.callback = callback; - } + // eslint-disable-next-line no-unused-vars + define = (name, deps, callback) => { + let value = {}; - registry[name] = value; - }; - - require = function (name) { - return internalRequire(name, null); - }; + if (!callback) { + value.deps = []; + value.callback = deps; + } else { + value.deps = deps; + value.callback = callback; + } - // setup `require` module - require['default'] = require; + registry[name] = value; + }; - require.has = function registryHas(moduleName) { - return Boolean(registry[moduleName]) || Boolean(registry[moduleName + '/index']); - }; + // setup `require` module + require['default'] = require; - require._eak_seen = registry; + require.has = function registryHas(moduleName) { + return Boolean(registry[moduleName]) || Boolean(registry[moduleName + '/index']); + }; - Ember.__loader = { - define: define, - require: require, - registry: registry, - }; - } else { - define = Ember.__loader.define; - require = Ember.__loader.require; - } + require._eak_seen = registry; })(); diff --git a/packages/node-module/index.d.ts b/packages/node-module/index.d.ts deleted file mode 100644 index 249e58d812f..00000000000 --- a/packages/node-module/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const IS_NODE: boolean; - -export function require(url: string): string; diff --git a/packages/node-module/index.js b/packages/node-module/index.js deleted file mode 100644 index cad5138a421..00000000000 --- a/packages/node-module/index.js +++ /dev/null @@ -1,16 +0,0 @@ -/*global module */ - -const IS_NODE = typeof module === 'object' && typeof module.require === 'function'; - -let exportModule; -let exportRequire; - -if (IS_NODE) { - exportModule = module; - exportRequire = module.require; -} else { - exportModule = null; - exportRequire = null; -} - -export { IS_NODE, exportModule as module, exportRequire as require }; diff --git a/packages/node-module/require.d.ts b/packages/node-module/require.d.ts deleted file mode 100644 index 58443c7f54c..00000000000 --- a/packages/node-module/require.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module 'require' { - export function has(path: string): boolean; - export default function require(path: string): any; -} diff --git a/tests/index.html b/tests/index.html index 57bf6b6b84d..9349283ad8a 100644 --- a/tests/index.html +++ b/tests/index.html @@ -10,10 +10,14 @@ } + @@ -114,7 +118,7 @@ } } - var setupQUnit = window.Ember.__loader.require('internal-test-helpers/lib/ember-dev/setup-qunit')['default']; + var setupQUnit = require('internal-test-helpers/lib/ember-dev/setup-qunit')['default']; setupQUnit(); // Tests should time out after 15 seconds @@ -180,11 +184,11 @@ skipPackages = (skipPackages && skipPackages.split(',')) || []; var skipPackageRegexp = new RegExp('^('+skipPackages.join('|')+')/'); - for (var moduleName in Ember.__loader.registry) { + for (var moduleName in require._eak_seen) { if (!moduleName.match(packageRegexp)) { continue; } if (moduleName.match(skipPackageRegexp)) { continue; } - if (moduleName.match(/[_-]test$/)) { Ember.__loader.require(moduleName); } + if (moduleName.match(/[_-]test$/)) { require(moduleName); } }