Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🏗 Use ESM to import peer Bento binaries (#37586)
On `module` builds, use browser's `import` statement to share Bento dependencies like `bento.mjs`. On `nomodule` builds, we can't use `import`. Instead, we use babel to output to a format similar to AMD. This change also simplifies some aspects: - Prefers using `{remapDependencies}` for esbuild rather than `module-resolver` on babel. - Removes `bento` compile wrapper. - Removes generators. Uses `src/bento.js` directly, and the intermediate `bento-shared.js` module is no longer needed.
- Loading branch information
1 parent
37aac3c
commit b6877bd
Showing
43 changed files
with
756 additions
and
582 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/** @return {{[string: string]: any}} */ | ||
function getNoModuleLoaderConfig() { | ||
return { | ||
plugins: ['./build-system/babel-plugins/babel-plugin-nomodule-loader'], | ||
}; | ||
} | ||
|
||
module.exports = { | ||
getNoModuleLoaderConfig, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
build-system/babel-plugins/babel-plugin-nomodule-loader/define-template.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// @ts-nocheck | ||
/* eslint-disable no-var */ | ||
/* eslint-disable @typescript-eslint/no-unused-vars */ | ||
|
||
/* global __MODULE_NAME__ */ | ||
/* global __HAS_EXPORTS__ */ | ||
/* global __IMPORT_NAMES__ */ | ||
/* global __SINGLE_IMPORT_NO_EXPORTS__ */ | ||
/* global __ONLY_EXPORTS__ */ | ||
|
||
/** | ||
* An async module loader similar to define() in AMD. | ||
* Our implementation varies in that it can be compiled down to a minimal form | ||
* based on the module's needs, rather than bundling a full implementation. | ||
*/ | ||
(function defineish(defineCallback) { | ||
// self.BENTO maps module names to callbacks to execute with their contents. | ||
// interface ModuleCallbacks { | ||
// [name: string]: ((Object) => void)[], | ||
// } | ||
var callbacks = (self.BENTO = self.BENTO || {}); | ||
var exec = __HAS_EXPORTS__ | ||
? function (_exports) { | ||
defineCallback.apply(null, arguments); | ||
var name = __MODULE_NAME__; | ||
var awaiting = (callbacks[name] = callbacks[name] || []); | ||
while (awaiting.length) { | ||
awaiting.pop()(_exports); | ||
} | ||
awaiting.push = function (callback) { | ||
callback(_exports); | ||
}; | ||
} | ||
: defineCallback; | ||
// The most common cases are ONLY_EXPORTS and SINGLE_IMPORT_NO_EXPORTS. | ||
// We provide them with single-purpose implementations whose output is | ||
// significantly smaller than the worst case. | ||
if (__ONLY_EXPORTS__) { | ||
exec({}); | ||
} else if (__SINGLE_IMPORT_NO_EXPORTS__) { | ||
var name = __SINGLE_IMPORT_NO_EXPORTS__; | ||
(callbacks[name] = callbacks[name] || []).push(exec); | ||
} else { | ||
// Fallback general purpose implementation. | ||
Promise.all( | ||
__IMPORT_NAMES__.map(function (name) { | ||
// exports is identified as the number 0 | ||
if (__HAS_EXPORTS__ && name === 0) { | ||
return {}; | ||
} | ||
return new Promise(function (resolve) { | ||
(callbacks[name] = callbacks[name] || []).push(resolve); | ||
}); | ||
}) | ||
).then(function (modules) { | ||
exec.apply(null, modules); | ||
}); | ||
} | ||
})(function (__CALLBACK_ARGS__) {}); |
125 changes: 125 additions & 0 deletions
125
build-system/babel-plugins/babel-plugin-nomodule-loader/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
/** | ||
* @fileoverview | ||
* Transforms ESM import statements into an async loader meant for `nomodule` | ||
* builds. | ||
*/ | ||
|
||
const { | ||
buildNamespaceInitStatements, | ||
ensureStatementsHoisted, | ||
hasExports, | ||
isModule, | ||
rewriteModuleStatementsAndPrepareHeader, | ||
} = require('@babel/helper-module-transforms'); | ||
const {readFileSync} = require('fs'); | ||
const {join: pathJoin, posix, relative} = require('path'); | ||
|
||
let wrapperTemplate; | ||
|
||
module.exports = function (babel) { | ||
const {template, types: t} = babel; | ||
|
||
const pathToModuleName = (filename) => | ||
filename.replace(/^(\.\/)?dist\//, '').replace(/(\.max)?\.m?js$/, ''); | ||
|
||
const resolveModuleName = (filename, source) => | ||
pathToModuleName(posix.join(posix.dirname(filename), source)); | ||
|
||
/** | ||
* @param {Object} replacements | ||
* @return {babel.Node} | ||
*/ | ||
function buildWrapper(replacements) { | ||
if (!wrapperTemplate) { | ||
const templateSource = readFileSync( | ||
pathJoin(__dirname, 'define-template.js'), | ||
'utf8' | ||
); | ||
wrapperTemplate = template(templateSource, { | ||
placeholderPattern: /^__[A-Z0-9_]+__$/, | ||
}); | ||
} | ||
return wrapperTemplate(replacements); | ||
} | ||
|
||
/** | ||
* @param {babel.NodePath<import('@babel/types').Program>} path | ||
* @param {babel.Node} wrapper | ||
*/ | ||
function injectWrapper(path, wrapper) { | ||
const {body, directives} = path.node; | ||
path.node.directives = []; | ||
path.node.body = []; | ||
const wrapperPath = path.pushContainer('body', wrapper)[0]; | ||
const callback = wrapperPath | ||
.get('expression.arguments') | ||
// @ts-ignore | ||
.filter((arg) => arg.isFunctionExpression())[0] | ||
.get('body'); | ||
callback.pushContainer('directives', directives); | ||
callback.pushContainer('body', body); | ||
} | ||
|
||
return { | ||
name: 'nomodule-loader', | ||
visitor: { | ||
Program: { | ||
enter(path, state) { | ||
// We can stop since this should be the last transform step. | ||
// See nomodule-loader-config.js | ||
path.stop(); | ||
|
||
if (!isModule(path)) { | ||
throw new Error(); | ||
} | ||
const loose = true; | ||
const noInterop = true; | ||
const {headers, meta} = rewriteModuleStatementsAndPrepareHeader( | ||
path, | ||
{loose, noInterop} | ||
); | ||
|
||
const filename = relative(process.cwd(), state.filename); | ||
const importNames = []; | ||
const callbackArgs = []; | ||
const metaHasExports = hasExports(meta); | ||
if (metaHasExports) { | ||
// exports is identified as the number 0 | ||
importNames.push(t.numericLiteral(0)); | ||
callbackArgs.push(t.identifier(meta.exportName)); | ||
} | ||
for (const [source, metadata] of meta.source) { | ||
importNames.push( | ||
t.stringLiteral(resolveModuleName(filename, source)) | ||
); | ||
callbackArgs.push(t.identifier(metadata.name)); | ||
headers.push( | ||
...buildNamespaceInitStatements(meta, metadata, loose) | ||
); | ||
} | ||
if (importNames.length < 1) { | ||
return; | ||
} | ||
ensureStatementsHoisted(headers); | ||
path.unshiftContainer('body', headers); | ||
injectWrapper( | ||
path, | ||
buildWrapper({ | ||
__MODULE_NAME__: t.stringLiteral(pathToModuleName(filename)), | ||
__HAS_EXPORTS__: t.booleanLiteral(metaHasExports), | ||
__ONLY_EXPORTS__: t.booleanLiteral( | ||
metaHasExports && importNames.length === 1 | ||
), | ||
__IMPORT_NAMES__: t.arrayExpression(importNames), | ||
__SINGLE_IMPORT_NO_EXPORTS__: | ||
importNames.length === 1 && !metaHasExports | ||
? t.cloneNode(importNames[0]) | ||
: t.nullLiteral(), | ||
__CALLBACK_ARGS__: callbackArgs, | ||
}) | ||
); | ||
}, | ||
}, | ||
}, | ||
}; | ||
}; |
1 change: 1 addition & 0 deletions
1
...bel-plugins/babel-plugin-nomodule-loader/test/fixtures/transform/export-default/input.mjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export default function fn() {} |
5 changes: 5 additions & 0 deletions
5
...-plugins/babel-plugin-nomodule-loader/test/fixtures/transform/export-default/options.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"plugins": [ | ||
"../../../.." | ||
] | ||
} |
42 changes: 42 additions & 0 deletions
42
...bel-plugins/babel-plugin-nomodule-loader/test/fixtures/transform/export-default/output.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
(function defineish(defineCallback) { | ||
var callbacks = self.BENTO = self.BENTO || {}; | ||
var exec = true ? function (_exports) { | ||
defineCallback.apply(null, arguments); | ||
var name = "build-system/babel-plugins/babel-plugin-nomodule-loader/test/fixtures/transform/export-default/input"; | ||
var awaiting = callbacks[name] = callbacks[name] || []; | ||
|
||
while (awaiting.length) { | ||
awaiting.pop()(_exports); | ||
} | ||
|
||
awaiting.push = function (callback) { | ||
callback(_exports); | ||
}; | ||
} : defineCallback; | ||
|
||
if (true) { | ||
exec({}); | ||
} else if (null) { | ||
var name = null; | ||
(callbacks[name] = callbacks[name] || []).push(exec); | ||
} else { | ||
Promise.all([0].map(function (name) { | ||
if (true && name === 0) { | ||
return {}; | ||
} | ||
|
||
return new Promise(function (resolve) { | ||
(callbacks[name] = callbacks[name] || []).push(resolve); | ||
}); | ||
})).then(function (modules) { | ||
exec.apply(null, modules); | ||
}); | ||
} | ||
})(function (_exports) { | ||
"use strict"; | ||
|
||
_exports.__esModule = true; | ||
_exports.default = fn; | ||
|
||
function fn() {} | ||
}); |
1 change: 1 addition & 0 deletions
1
.../babel-plugins/babel-plugin-nomodule-loader/test/fixtures/transform/export-from/input.mjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export {x, y, z} from './abc'; |
5 changes: 5 additions & 0 deletions
5
...bel-plugins/babel-plugin-nomodule-loader/test/fixtures/transform/export-from/options.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"plugins": [ | ||
"../../../.." | ||
] | ||
} |
43 changes: 43 additions & 0 deletions
43
.../babel-plugins/babel-plugin-nomodule-loader/test/fixtures/transform/export-from/output.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
(function defineish(defineCallback) { | ||
var callbacks = self.BENTO = self.BENTO || {}; | ||
var exec = true ? function (_exports) { | ||
defineCallback.apply(null, arguments); | ||
var name = "build-system/babel-plugins/babel-plugin-nomodule-loader/test/fixtures/transform/export-from/input"; | ||
var awaiting = callbacks[name] = callbacks[name] || []; | ||
|
||
while (awaiting.length) { | ||
awaiting.pop()(_exports); | ||
} | ||
|
||
awaiting.push = function (callback) { | ||
callback(_exports); | ||
}; | ||
} : defineCallback; | ||
|
||
if (false) { | ||
exec({}); | ||
} else if (null) { | ||
var name = null; | ||
(callbacks[name] = callbacks[name] || []).push(exec); | ||
} else { | ||
Promise.all([0, "build-system/babel-plugins/babel-plugin-nomodule-loader/test/fixtures/transform/export-from/abc"].map(function (name) { | ||
if (true && name === 0) { | ||
return {}; | ||
} | ||
|
||
return new Promise(function (resolve) { | ||
(callbacks[name] = callbacks[name] || []).push(resolve); | ||
}); | ||
})).then(function (modules) { | ||
exec.apply(null, modules); | ||
}); | ||
} | ||
})(function (_exports, _abc) { | ||
"use strict"; | ||
|
||
_exports.__esModule = true; | ||
_exports.z = _exports.y = _exports.x = void 0; | ||
_exports.x = _abc.x; | ||
_exports.y = _abc.y; | ||
_exports.z = _abc.z; | ||
}); |
Oops, something went wrong.