From 2b596c8c8b8706a321cf40d3564aa984781f99cf Mon Sep 17 00:00:00 2001 From: John McLaughlin Date: Sun, 18 Jun 2017 19:49:16 +0700 Subject: [PATCH] Support es2015 module exports (Babel, TypeScript) Detect when a script file is an es2015 module created by a transpiler like Babel or TypeScript and use the `default` export instead of `module.exports` in such case. The following artefacts support the new syntax now: - boot scripts - components - middleware - model scripts --- lib/compiler.js | 5 +++-- lib/executor.js | 15 ++++++++------- lib/require.js | 9 +++++++++ test/browser.test.js | 12 +++++++++--- test/executor.test.js | 3 +++ test/fixtures/browser-app/component-config.json | 3 +++ .../browser-app/components/dummy-component-umd.js | 11 +++++++++++ test/fixtures/browser-app/mixins/audited-umd.js | 11 +++++++++++ test/fixtures/browser-app/model-config.json | 3 +++ test/fixtures/browser-app/models/product-umd.js | 11 +++++++++++ test/fixtures/browser-app/models/product-umd.json | 5 +++++ test/fixtures/simple-app/boot/umd.js | 11 +++++++++++ test/fixtures/simple-app/middleware.json | 5 ++++- test/helpers/set-umd-middleware.js | 14 ++++++++++++++ 14 files changed, 105 insertions(+), 13 deletions(-) create mode 100644 lib/require.js create mode 100644 test/fixtures/browser-app/components/dummy-component-umd.js create mode 100644 test/fixtures/browser-app/mixins/audited-umd.js create mode 100644 test/fixtures/browser-app/models/product-umd.js create mode 100644 test/fixtures/browser-app/models/product-umd.json create mode 100644 test/fixtures/simple-app/boot/umd.js create mode 100644 test/helpers/set-umd-middleware.js diff --git a/lib/compiler.js b/lib/compiler.js index b362453..7ba166e 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -14,6 +14,7 @@ var debug = require('debug')('loopback:boot:compiler'); var Module = require('module'); var _ = require('lodash'); var g = require('strong-globalize')(); +var requireNodeOrEsModule = require('./require'); var FILE_EXTENSION_JSON = '.json'; @@ -589,7 +590,7 @@ function resolveMiddlewarePath(rootDir, middleware, config) { // Try to require the module and check if . is a valid // function - var m = require(sourceFile); + var m = requireNodeOrEsModule(sourceFile); if (typeof m[fragment] === 'function') { resolved.sourceFile = sourceFile; return resolved; @@ -778,7 +779,7 @@ function loadMixins(sourceFiles, normalization) { meta.name = name; if (utils.fileExistsSync(metafile)) { // May overwrite name, not sourceFile - _.extend(meta, require(metafile)); + _.extend(meta, requireNodeOrEsModule(metafile)); } meta.sourceFile = filepath; mixinInstructions[meta.name] = meta; diff --git a/lib/executor.js b/lib/executor.js index 17fc02d..a025cf1 100644 --- a/lib/executor.js +++ b/lib/executor.js @@ -10,6 +10,7 @@ var async = require('async'); var path = require('path'); var format = require('util').format; var g = require('strong-globalize')(); +var requireNodeOrEsModule = require('./require'); /** * Execute bootstrap instructions gathered by `boot.compile`. @@ -211,7 +212,7 @@ function defineMixins(app, instructions) { if (!modelBuilder.mixins || !mixins.length) return; mixins.forEach(function(obj) { - var mixin = require(obj.sourceFile); + var mixin = requireNodeOrEsModule(obj.sourceFile); if (typeof mixin === 'function' || mixin.prototype instanceof BaseClass) { debug('Defining mixin %s', obj.name); @@ -244,7 +245,7 @@ function defineModels(app, instructions) { model = registry.createModel(data.definition); if (data.sourceFile) { debug('Loading customization script %s', data.sourceFile); - var code = require(data.sourceFile); + var code = requireNodeOrEsModule(data.sourceFile); if (typeof code === 'function') { debug('Customizing model %s', name); code(model); @@ -288,12 +289,12 @@ function runScripts(app, list, callback) { list.forEach(function(filepath) { debug('Requiring script %s', filepath); try { - var exports = require(filepath); - if (typeof exports === 'function') { + var bootFn = requireNodeOrEsModule(filepath); + if (typeof bootFn === 'function') { debug('Exported function detected %s', filepath); functions.push({ path: filepath, - func: exports, + func: bootFn, }); } } catch (err) { @@ -340,7 +341,7 @@ function setupMiddleware(app, instructions) { middleware.forEach(function(data) { debug('Configuring middleware %j%s', data.sourceFile, data.fragment ? ('#' + data.fragment) : ''); - var factory = require(data.sourceFile); + var factory = requireNodeOrEsModule(data.sourceFile); if (data.fragment) { factory = factory[data.fragment].bind(factory); } @@ -429,7 +430,7 @@ function getUpdatedConfigObject(app, config, opts) { function setupComponents(app, instructions) { instructions.components.forEach(function(data) { debug('Configuring component %j', data.sourceFile); - var configFn = require(data.sourceFile); + var configFn = requireNodeOrEsModule(data.sourceFile); var opts = { useEnvVars: true, }; diff --git a/lib/require.js b/lib/require.js new file mode 100644 index 0000000..a2d5296 --- /dev/null +++ b/lib/require.js @@ -0,0 +1,9 @@ +// Copyright IBM Corp. 2015,2017. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +module.exports = function requireNodeOrEsModule(sourceFile) { + var exports = require(sourceFile); + return exports && exports.__esModule ? exports.default : exports; +}; diff --git a/test/browser.test.js b/test/browser.test.js index d179aa5..5677383 100644 --- a/test/browser.test.js +++ b/test/browser.test.js @@ -57,10 +57,15 @@ describe('browser support', function() { expect(Object.keys(app.models)).to.include('Customer'); expect(app.models.Customer.settings) .to.have.property('_customized', 'Customer'); + expect(Object.keys(app.models)).to.include('ProductUmd'); + expect(app.models.ProductUmd.settings) + .to.have.property('_customized', 'UMD'); - // configured in fixtures/browser-app/component-config.json - // and fixtures/browser-app/components/dummy-component.js + // configured in fixtures/browser-app/component-config.json, + // fixtures/browser-app/components/dummy-component.js and + // fixtures/browser-app/components/dummy-component-umd.js expect(app.dummyComponentOptions).to.eql({ option: 'value' }); + expect(app.dummyComponentUmdOptions).to.eql({ option: 'valueUmd' }); done(); }); @@ -79,8 +84,9 @@ describe('browser support', function() { var modelBuilder = app.registry.modelBuilder; var registry = modelBuilder.mixins.mixins; - expect(Object.keys(registry)).to.eql(['TimeStamps']); + expect(Object.keys(registry)).to.eql(['AuditedUmd', 'TimeStamps']); expect(app.models.Customer.timeStampsMixin).to.eql(true); + expect(app.models.ProductUmd.auditedMixin).to.eql(true); done(); }); diff --git a/test/executor.test.js b/test/executor.test.js index 7d00b10..bdaf3e3 100644 --- a/test/executor.test.js +++ b/test/executor.test.js @@ -278,6 +278,7 @@ describe('executor', function() { 'barStarted', 'barFinished', 'barSyncExecuted', + 'umdLoaded', ]); done(); }, 10); @@ -294,6 +295,7 @@ describe('executor', function() { 'barStarted', 'barFinished', 'barSyncExecuted', + 'umdLoaded', ]); done(); }); @@ -838,6 +840,7 @@ describe('executor', function() { .end(function(err, res) { if (err) return done(err); expect(res.headers.names).to.equal('custom-middleware'); + expect(res.headers.umd).to.equal('success'); done(); }); }); diff --git a/test/fixtures/browser-app/component-config.json b/test/fixtures/browser-app/component-config.json index 3aa8175..dfff385 100644 --- a/test/fixtures/browser-app/component-config.json +++ b/test/fixtures/browser-app/component-config.json @@ -1,5 +1,8 @@ { "./components/dummy-component": { "option": "value" + }, + "./components/dummy-component-umd": { + "option": "valueUmd" } } diff --git a/test/fixtures/browser-app/components/dummy-component-umd.js b/test/fixtures/browser-app/components/dummy-component-umd.js new file mode 100644 index 0000000..f57fd82 --- /dev/null +++ b/test/fixtures/browser-app/components/dummy-component-umd.js @@ -0,0 +1,11 @@ +// Copyright IBM Corp. 2015,2017. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +module.exports = { + default: function(app, options) { + app.dummyComponentUmdOptions = options; + }, +}; +Object.defineProperty(module.exports, '__esModule', { value: true }); diff --git a/test/fixtures/browser-app/mixins/audited-umd.js b/test/fixtures/browser-app/mixins/audited-umd.js new file mode 100644 index 0000000..e48f34c --- /dev/null +++ b/test/fixtures/browser-app/mixins/audited-umd.js @@ -0,0 +1,11 @@ +// Copyright IBM Corp. 2014,2017. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +module.exports = { + default: function(Model, options) { + Model.auditedMixin = true; + }, +}; +Object.defineProperty(module.exports, '__esModule', { value: true }); diff --git a/test/fixtures/browser-app/model-config.json b/test/fixtures/browser-app/model-config.json index c0686a2..6112377 100644 --- a/test/fixtures/browser-app/model-config.json +++ b/test/fixtures/browser-app/model-config.json @@ -7,5 +7,8 @@ }, "Customer": { "dataSource": "db" + }, + "ProductUmd": { + "dataSource": "db" } } diff --git a/test/fixtures/browser-app/models/product-umd.js b/test/fixtures/browser-app/models/product-umd.js new file mode 100644 index 0000000..452339c --- /dev/null +++ b/test/fixtures/browser-app/models/product-umd.js @@ -0,0 +1,11 @@ +// Copyright IBM Corp. 2014,2017. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +module.exports = { + default: function(ProductUmd) { + ProductUmd.settings._customized = 'UMD'; + }, +}; +Object.defineProperty(module.exports, '__esModule', { value: true }); diff --git a/test/fixtures/browser-app/models/product-umd.json b/test/fixtures/browser-app/models/product-umd.json new file mode 100644 index 0000000..b224205 --- /dev/null +++ b/test/fixtures/browser-app/models/product-umd.json @@ -0,0 +1,5 @@ +{ + "name": "ProductUmd", + "base": "User", + "mixins": {"AuditedUmd": {} } +} diff --git a/test/fixtures/simple-app/boot/umd.js b/test/fixtures/simple-app/boot/umd.js new file mode 100644 index 0000000..976f69b --- /dev/null +++ b/test/fixtures/simple-app/boot/umd.js @@ -0,0 +1,11 @@ +// Copyright IBM Corp. 2014,2017. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +module.exports = { + default: function(app) { + process.bootFlags.push('umdLoaded'); + }, +}; +Object.defineProperty(module.exports, '__esModule', { value: true }); diff --git a/test/fixtures/simple-app/middleware.json b/test/fixtures/simple-app/middleware.json index 3062e34..57df770 100644 --- a/test/fixtures/simple-app/middleware.json +++ b/test/fixtures/simple-app/middleware.json @@ -2,6 +2,9 @@ "initial": { "../../helpers/push-name-middleware": { "params": "custom-middleware" - } + }, + "../../helpers/set-umd-middleware": { + "params": "success" + } } } diff --git a/test/helpers/set-umd-middleware.js b/test/helpers/set-umd-middleware.js new file mode 100644 index 0000000..962eea4 --- /dev/null +++ b/test/helpers/set-umd-middleware.js @@ -0,0 +1,14 @@ +// Copyright IBM Corp. 2017. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +module.exports = { + default: function(value) { + return function(req, res, next) { + res.setHeader('umd', value); + next(); + }; + }, +}; +Object.defineProperty(module.exports, '__esModule', { value: true });