DEV: Improve Ember module shims under Ember CLI (#15795)
In our legacy environment, Ember RFC176 shims are included in `discourse-loader.js` which is part of the `vendor.js` bundle. This meant that the module shims were available as soon as the vendor.js asset was loaded. Under Ember CLI, we were defining these shims in `discourse-boot.js`. This is loaded by the browser much later, and meant that the shims were not available to themes/plugins that call `require()` before Discourse has booted. This was causing errors under some circumstances. This commit refactors the Ember CLI implementation so that the shims are included in the vendor.js bundle. This is done via an addon which leans on the ember-rfc176-data NPM package. This will ensure we have all the definitions, without the need for manual copy/paste.
This commit is contained in:
parent
7e67c5c8a8
commit
7933278ef4
|
@ -110,6 +110,11 @@ module.exports = function (defaults) {
|
|||
});
|
||||
app.import(discourseRoot + "/app/assets/javascripts/polyfills.js");
|
||||
|
||||
app.import(
|
||||
discourseRoot +
|
||||
"/app/assets/javascripts/discourse/public/assets/scripts/module-shims.js"
|
||||
);
|
||||
|
||||
const mergedTree = mergeTrees([
|
||||
discourseScss(`${discourseRoot}/app/assets/stylesheets`, "testem.scss"),
|
||||
createI18nTree(discourseRoot, vendorJs),
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
engine-strict = true
|
|
@ -0,0 +1,57 @@
|
|||
"use strict";
|
||||
|
||||
// In core, babel-plugin-ember-modules-api-polyfill takes care of re-writing the new module
|
||||
// syntax to the legacy Ember globals. For themes and plugins, we need to manually set up
|
||||
// the modules.
|
||||
//
|
||||
// Eventually, Ember RFC176 will be implemented, and we can drop these shims.
|
||||
|
||||
const RFC176Data = require("ember-rfc176-data");
|
||||
|
||||
module.exports = {
|
||||
name: require("./package").name,
|
||||
|
||||
isDevelopingAddon() {
|
||||
return true;
|
||||
},
|
||||
|
||||
contentFor: function (type) {
|
||||
if (type !== "vendor-suffix") {
|
||||
return;
|
||||
}
|
||||
|
||||
const modules = {};
|
||||
|
||||
for (const entry of RFC176Data) {
|
||||
// Entries look like:
|
||||
// {
|
||||
// global: 'Ember.expandProperties',
|
||||
// module: '@ember/object/computed',
|
||||
// export: 'expandProperties',
|
||||
// deprecated: false
|
||||
// },
|
||||
|
||||
if (entry.deprecated) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let m = modules[entry.module];
|
||||
if (!m) {
|
||||
m = modules[entry.module] = [];
|
||||
}
|
||||
|
||||
m.push(entry);
|
||||
}
|
||||
|
||||
let output = "";
|
||||
for (const moduleName of Object.keys(modules)) {
|
||||
const exports = modules[moduleName];
|
||||
const rawExports = exports
|
||||
.map((e) => `${e.export}:${e.global}`)
|
||||
.join(",");
|
||||
output += `define("${moduleName}", () => {return {${rawExports}}});\n`;
|
||||
}
|
||||
|
||||
return output;
|
||||
},
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "rfc176-shims",
|
||||
"keywords": [
|
||||
"ember-addon"
|
||||
]
|
||||
}
|
|
@ -49,6 +49,7 @@
|
|||
"ember-load-initializers": "^2.1.1",
|
||||
"ember-maybe-import-regenerator": "^0.1.6",
|
||||
"ember-qunit": "^5.1.2",
|
||||
"ember-rfc176-data": "^0.3.17",
|
||||
"ember-source": "~3.15.0",
|
||||
"ember-test-selectors": "^6.0.0",
|
||||
"eslint": "^7.27.0",
|
||||
|
@ -79,7 +80,8 @@
|
|||
},
|
||||
"ember-addon": {
|
||||
"paths": [
|
||||
"lib/bootstrap-json"
|
||||
"lib/bootstrap-json",
|
||||
"lib/rfc176-shims"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -2,157 +2,6 @@
|
|||
if (window.unsupportedBrowser) {
|
||||
throw "Unsupported browser detected";
|
||||
}
|
||||
// TODO: These are needed to load plugins because @ember has its own loader.
|
||||
// We should find a nicer way to do this.
|
||||
const EMBER_MODULES = {
|
||||
"@ember/application": {
|
||||
default: Ember.Application,
|
||||
setOwner: Ember.setOwner,
|
||||
getOwner: Ember.getOwner,
|
||||
},
|
||||
"@ember/array": {
|
||||
default: Ember.Array,
|
||||
A: Ember.A,
|
||||
isArray: Ember.isArray,
|
||||
},
|
||||
"@ember/array/proxy": {
|
||||
default: Ember.ArrayProxy,
|
||||
},
|
||||
"@ember/component": {
|
||||
default: Ember.Component,
|
||||
},
|
||||
"@ember/component/helper": {
|
||||
default: Ember.Helper,
|
||||
},
|
||||
"@ember/component/text-field": {
|
||||
default: Ember.TextField,
|
||||
},
|
||||
"@ember/component/text-area": {
|
||||
default: Ember.TextArea,
|
||||
},
|
||||
"@ember/controller": {
|
||||
default: Ember.Controller,
|
||||
inject: Ember.inject.controller,
|
||||
},
|
||||
"@ember/debug": {
|
||||
warn: Ember.warn,
|
||||
},
|
||||
"@ember/error": {
|
||||
default: Ember.error,
|
||||
},
|
||||
"@ember/object": {
|
||||
action: Ember._action,
|
||||
default: Ember.Object,
|
||||
get: Ember.get,
|
||||
getProperties: Ember.getProperties,
|
||||
set: Ember.set,
|
||||
setProperties: Ember.setProperties,
|
||||
computed: Ember.computed,
|
||||
defineProperty: Ember.defineProperty,
|
||||
},
|
||||
"@ember/object/computed": {
|
||||
alias: Ember.computed.alias,
|
||||
and: Ember.computed.and,
|
||||
bool: Ember.computed.bool,
|
||||
collect: Ember.computed.collect,
|
||||
deprecatingAlias: Ember.computed.deprecatingAlias,
|
||||
empty: Ember.computed.empty,
|
||||
equal: Ember.computed.equal,
|
||||
filter: Ember.computed.filter,
|
||||
filterBy: Ember.computed.filterBy,
|
||||
gt: Ember.computed.gt,
|
||||
gte: Ember.computed.gte,
|
||||
intersect: Ember.computed.intersect,
|
||||
lt: Ember.computed.lt,
|
||||
lte: Ember.computed.lte,
|
||||
map: Ember.computed.map,
|
||||
mapBy: Ember.computed.mapBy,
|
||||
match: Ember.computed.match,
|
||||
max: Ember.computed.max,
|
||||
min: Ember.computed.min,
|
||||
none: Ember.computed.none,
|
||||
not: Ember.computed.not,
|
||||
notEmpty: Ember.computed.notEmpty,
|
||||
oneWay: Ember.computed.oneWay,
|
||||
or: Ember.computed.or,
|
||||
readOnly: Ember.computed.readOnly,
|
||||
reads: Ember.computed.reads,
|
||||
setDiff: Ember.computed.setDiff,
|
||||
sort: Ember.computed.sort,
|
||||
sum: Ember.computed.sum,
|
||||
union: Ember.computed.union,
|
||||
uniq: Ember.computed.uniq,
|
||||
uniqBy: Ember.computed.uniqBy,
|
||||
},
|
||||
"@ember/object/internals": {
|
||||
guidFor: Ember.guidFor,
|
||||
},
|
||||
"@ember/object/mixin": { default: Ember.Mixin },
|
||||
"@ember/object/proxy": { default: Ember.ObjectProxy },
|
||||
"@ember/object/promise-proxy-mixin": { default: Ember.PromiseProxyMixin },
|
||||
"@ember/object/evented": {
|
||||
default: Ember.Evented,
|
||||
on: Ember.on,
|
||||
},
|
||||
"@ember/routing/route": { default: Ember.Route },
|
||||
"@ember/routing/router": { default: Ember.Router },
|
||||
"@ember/runloop": {
|
||||
bind: Ember.run.bind,
|
||||
cancel: Ember.run.cancel,
|
||||
debounce: Ember.testing ? Ember.run : Ember.run.debounce,
|
||||
later: Ember.run.later,
|
||||
next: Ember.run.next,
|
||||
once: Ember.run.once,
|
||||
run: Ember.run,
|
||||
schedule: Ember.run.schedule,
|
||||
scheduleOnce: Ember.run.scheduleOnce,
|
||||
throttle: Ember.run.throttle,
|
||||
},
|
||||
"@ember/service": {
|
||||
default: Ember.Service,
|
||||
inject: Ember.inject.service,
|
||||
},
|
||||
"@ember/string": {
|
||||
w: Ember.String.w,
|
||||
dasherize: Ember.String.dasherize,
|
||||
decamelize: Ember.String.decamelize,
|
||||
camelize: Ember.String.camelize,
|
||||
classify: Ember.String.classify,
|
||||
underscore: Ember.String.underscore,
|
||||
capitalize: Ember.String.capitalize,
|
||||
},
|
||||
"@ember/template": {
|
||||
htmlSafe: Ember.String.htmlSafe,
|
||||
},
|
||||
"@ember/utils": {
|
||||
isBlank: Ember.isBlank,
|
||||
isEmpty: Ember.isEmpty,
|
||||
isNone: Ember.isNone,
|
||||
isPresent: Ember.isPresent,
|
||||
},
|
||||
jquery: { default: $ },
|
||||
rsvp: {
|
||||
asap: Ember.RSVP.asap,
|
||||
all: Ember.RSVP.all,
|
||||
allSettled: Ember.RSVP.allSettled,
|
||||
race: Ember.RSVP.race,
|
||||
hash: Ember.RSVP.hash,
|
||||
hashSettled: Ember.RSVP.hashSettled,
|
||||
rethrow: Ember.RSVP.rethrow,
|
||||
defer: Ember.RSVP.defer,
|
||||
denodeify: Ember.RSVP.denodeify,
|
||||
resolve: Ember.RSVP.resolve,
|
||||
reject: Ember.RSVP.reject,
|
||||
map: Ember.RSVP.map,
|
||||
filter: Ember.RSVP.filter,
|
||||
default: Ember.RSVP,
|
||||
Promise: Ember.RSVP.Promise,
|
||||
EventTarget: Ember.RSVP.EventTarget,
|
||||
},
|
||||
};
|
||||
Object.keys(EMBER_MODULES).forEach((mod) => {
|
||||
define(mod, () => EMBER_MODULES[mod]);
|
||||
});
|
||||
|
||||
// TODO: Remove this and have resolver find the templates
|
||||
const prefix = "discourse/templates/";
|
||||
|
@ -166,15 +15,6 @@
|
|||
}
|
||||
});
|
||||
|
||||
define("I18n", ["exports"], function (exports) {
|
||||
return I18n;
|
||||
});
|
||||
|
||||
define("htmlbars-inline-precompile", ["exports"], function (exports) {
|
||||
exports.default = function tag(strings) {
|
||||
return Ember.Handlebars.compile(strings[0]);
|
||||
};
|
||||
});
|
||||
window.__widget_helpers = require("discourse-widget-hbs/helpers").default;
|
||||
|
||||
// TODO: Eliminate this global
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
define("I18n", ["exports"], function (exports) {
|
||||
return I18n;
|
||||
});
|
||||
|
||||
define("htmlbars-inline-precompile", ["exports"], function (exports) {
|
||||
exports.default = function tag(strings) {
|
||||
return Ember.Handlebars.compile(strings[0]);
|
||||
};
|
||||
});
|
Loading…
Reference in New Issue