-
-
Notifications
You must be signed in to change notification settings - Fork 108
/
Copy pathindex.js
91 lines (87 loc) · 2.77 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import babel from '@babel/standalone';
/** @param {import('../../types').Options} options */
export default function (options) {
if (options.mode && options.mode !== 'build') return;
options.plugins.push(nomodulePlugin({}));
}
/**
* @param {object} [options]
* @returns {import('rollup').Plugin}
*/
function nomodulePlugin({} = {}) {
return {
name: '@wmrjs/nomodule',
async generateBundle(opts, bundle) {
const downleveled = new Map();
for (const fileName in bundle) {
const chunk = bundle[fileName];
if (chunk.type !== 'chunk') continue;
const legacy = downlevel(chunk.code, fileName);
if (!legacy) continue;
const legacyFileName = chunk.fileName.replace(/\.js/, '.legacy.js');
this.emitFile({
type: 'asset',
fileName: legacyFileName,
source: legacy
});
downleveled.set(fileName, legacyFileName);
}
// Update all the HTML files with <script type=module> to add legacy loading via Shimport+Polyfills
for (const fileName in bundle) {
const asset = bundle[fileName];
if (asset.type !== 'asset' || typeof asset.source !== 'string' || !asset.fileName.match(/\.html$/)) continue;
if (!/<script(?:\s[^>]*)?\s+type=(['"])module\1/.test(asset.source)) continue;
// this is gross obviously
const POLYFILL = 'https://unpkg.com/@babel/[email protected]/browser.js'; // https://unpkg.com/regenerator-runtime
const script = `<script nomodule src="${POLYFILL}"></script><script nomodule src="${SHIMPORT}"></script><script nomodule>[].forEach.call(document.querySelectorAll('script[type=module]'),function(n){__shimport__.load(n.src.replace(/\\.js$/,'.legacy.js'))})</script>`;
if (/<\/body>/.test(asset.source)) {
asset.source = asset.source.replace(/<\/body>/, `${script}</body>`);
} else {
asset.source += script;
}
}
}
};
}
function downlevel(code, fileName) {
const result = babel.transform(code, {
compact: true,
minified: true,
configFile: false,
babelrc: false,
filename: fileName,
presets: [
[
'env',
{
targets: 'defaults',
shippedProposals: true,
loose: true,
bugfixes: true,
corejs: false,
useBuiltIns: false,
modules: false
}
]
],
plugins: [
{
visitor: {
ImportDeclaration(path) {
path.node.source.value = path.node.source.value.replace(/(\.legacy)?\.js$/, '.legacy.js');
},
Import(path) {
const p = path.parentPath;
if (!p.isCallExpression()) return;
const arg = p.get('arguments.0');
// the things I do to make TypeScript happy...
if (Array.isArray(arg) || !arg.isStringLiteral()) return;
arg.node.value = arg.node.value.replace(/(\.legacy)?\.js$/, '.legacy.js');
}
}
}
]
});
return result.code;
}