@vitejs/plugin-legacy 1.8.2 → 2.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js DELETED
@@ -1,712 +0,0 @@
1
- // @ts-check
2
- const path = require('path')
3
- const { createHash } = require('crypto')
4
- const { build } = require('vite')
5
- const MagicString = require('magic-string').default
6
-
7
- // lazy load babel since it's not used during dev
8
- let babel
9
- /**
10
- * @return {import('@babel/standalone')}
11
- */
12
- const loadBabel = () => babel || (babel = require('@babel/standalone'))
13
-
14
- // https://gist.github.com/samthor/64b114e4a4f539915a95b91ffd340acc
15
- // DO NOT ALTER THIS CONTENT
16
- const safari10NoModuleFix = `!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();`
17
-
18
- const legacyPolyfillId = 'vite-legacy-polyfill'
19
- const legacyEntryId = 'vite-legacy-entry'
20
- const systemJSInlineCode = `System.import(document.getElementById('${legacyEntryId}').getAttribute('data-src'))`
21
-
22
- const detectDynamicImportVarName = '__vite_is_dynamic_import_support'
23
- const detectDynamicImportCode = `try{import("_").catch(()=>1);}catch(e){}window.${detectDynamicImportVarName}=true;`
24
- const dynamicFallbackInlineCode = `!function(){if(window.${detectDynamicImportVarName})return;console.warn("vite: loading legacy build because dynamic import is unsupported, syntax error above should be ignored");var e=document.getElementById("${legacyPolyfillId}"),n=document.createElement("script");n.src=e.src,n.onload=function(){${systemJSInlineCode}},document.body.appendChild(n)}();`
25
-
26
- const forceDynamicImportUsage = `export function __vite_legacy_guard(){import('data:text/javascript,')};`
27
-
28
- const legacyEnvVarMarker = `__VITE_IS_LEGACY__`
29
-
30
- /**
31
- * @param {import('.').Options} options
32
- * @returns {import('vite').Plugin[]}
33
- */
34
- function viteLegacyPlugin(options = {}) {
35
- /**
36
- * @type {import('vite').ResolvedConfig}
37
- */
38
- let config
39
- const targets = options.targets || 'defaults'
40
- const genLegacy = options.renderLegacyChunks !== false
41
- const genDynamicFallback = genLegacy
42
-
43
- const debugFlags = (process.env.DEBUG || '').split(',')
44
- const isDebug =
45
- debugFlags.includes('vite:*') || debugFlags.includes('vite:legacy')
46
-
47
- const facadeToLegacyChunkMap = new Map()
48
- const facadeToLegacyPolyfillMap = new Map()
49
- const facadeToModernPolyfillMap = new Map()
50
- const modernPolyfills = new Set()
51
- // System JS relies on the Promise interface. It needs to be polyfilled for IE 11. (array.iterator is mandatory for supporting Promise.all)
52
- const DEFAULT_LEGACY_POLYFILL = [
53
- 'core-js/modules/es.promise',
54
- 'core-js/modules/es.array.iterator'
55
- ]
56
- const legacyPolyfills = new Set(DEFAULT_LEGACY_POLYFILL)
57
-
58
- if (Array.isArray(options.modernPolyfills)) {
59
- options.modernPolyfills.forEach((i) => {
60
- modernPolyfills.add(
61
- i.includes('/') ? `core-js/${i}` : `core-js/modules/${i}.js`
62
- )
63
- })
64
- }
65
- if (Array.isArray(options.polyfills)) {
66
- options.polyfills.forEach((i) => {
67
- if (i.startsWith(`regenerator`)) {
68
- legacyPolyfills.add(`regenerator-runtime/runtime.js`)
69
- } else {
70
- legacyPolyfills.add(
71
- i.includes('/') ? `core-js/${i}` : `core-js/modules/${i}.js`
72
- )
73
- }
74
- })
75
- }
76
- if (Array.isArray(options.additionalLegacyPolyfills)) {
77
- options.additionalLegacyPolyfills.forEach((i) => {
78
- legacyPolyfills.add(i)
79
- })
80
- }
81
-
82
- /**
83
- * @type {import('vite').Plugin}
84
- */
85
- const legacyConfigPlugin = {
86
- name: 'vite:legacy-config',
87
-
88
- apply: 'build',
89
- config(config) {
90
- if (!config.build) {
91
- config.build = {}
92
- }
93
-
94
- if (!config.build.cssTarget) {
95
- // Hint for esbuild that we are targeting legacy browsers when minifying CSS.
96
- // Full CSS compat table available at https://github.com/evanw/esbuild/blob/78e04680228cf989bdd7d471e02bbc2c8d345dc9/internal/compat/css_table.go
97
- // But note that only the `HexRGBA` feature affects the minify outcome.
98
- // HSL & rebeccapurple values will be minified away regardless the target.
99
- // So targeting `chrome61` suffices to fix the compatiblity issue.
100
- config.build.cssTarget = 'chrome61'
101
- }
102
- }
103
- }
104
-
105
- /**
106
- * @type {import('vite').Plugin}
107
- */
108
- const legacyGenerateBundlePlugin = {
109
- name: 'vite:legacy-generate-polyfill-chunk',
110
- apply: 'build',
111
-
112
- async generateBundle(opts, bundle) {
113
- if (config.build.ssr) {
114
- return
115
- }
116
-
117
- if (!isLegacyBundle(bundle, opts)) {
118
- if (!modernPolyfills.size) {
119
- return
120
- }
121
- isDebug &&
122
- console.log(
123
- `[@vitejs/plugin-legacy] modern polyfills:`,
124
- modernPolyfills
125
- )
126
- await buildPolyfillChunk(
127
- 'polyfills-modern',
128
- modernPolyfills,
129
- bundle,
130
- facadeToModernPolyfillMap,
131
- config.build,
132
- options.externalSystemJS
133
- )
134
- return
135
- }
136
-
137
- if (!genLegacy) {
138
- return
139
- }
140
-
141
- // legacy bundle
142
- if (legacyPolyfills.size || genDynamicFallback) {
143
- if (!legacyPolyfills.has('es.promise')) {
144
- // check if the target needs Promise polyfill because SystemJS relies
145
- // on it
146
- detectPolyfills(`Promise.resolve()`, targets, legacyPolyfills)
147
- }
148
-
149
- isDebug &&
150
- console.log(
151
- `[@vitejs/plugin-legacy] legacy polyfills:`,
152
- legacyPolyfills
153
- )
154
-
155
- await buildPolyfillChunk(
156
- 'polyfills-legacy',
157
- legacyPolyfills,
158
- bundle,
159
- facadeToLegacyPolyfillMap,
160
- // force using terser for legacy polyfill minification, since esbuild
161
- // isn't legacy-safe
162
- config.build,
163
- options.externalSystemJS
164
- )
165
- }
166
- }
167
- }
168
-
169
- /**
170
- * @type {import('vite').Plugin}
171
- */
172
- const legacyPostPlugin = {
173
- name: 'vite:legacy-post-process',
174
- enforce: 'post',
175
- apply: 'build',
176
-
177
- configResolved(_config) {
178
- if (_config.build.lib) {
179
- throw new Error('@vitejs/plugin-legacy does not support library mode.')
180
- }
181
- config = _config
182
-
183
- if (!genLegacy || config.build.ssr) {
184
- return
185
- }
186
-
187
- /**
188
- * @param {string | ((chunkInfo: import('rollup').PreRenderedChunk) => string)} fileNames
189
- * @param {string?} defaultFileName
190
- * @returns {string | ((chunkInfo: import('rollup').PreRenderedChunk) => string)}
191
- */
192
- const getLegacyOutputFileName = (
193
- fileNames,
194
- defaultFileName = '[name]-legacy.[hash].js'
195
- ) => {
196
- if (!fileNames) {
197
- return path.posix.join(config.build.assetsDir, defaultFileName)
198
- }
199
-
200
- return (chunkInfo) => {
201
- let fileName =
202
- typeof fileNames === 'function' ? fileNames(chunkInfo) : fileNames
203
-
204
- if (fileName.includes('[name]')) {
205
- // [name]-[hash].[format] -> [name]-legacy-[hash].[format]
206
- fileName = fileName.replace('[name]', '[name]-legacy')
207
- } else {
208
- // entry.js -> entry-legacy.js
209
- fileName = fileName.replace(/(.+)\.(.+)/, '$1-legacy.$2')
210
- }
211
-
212
- return fileName
213
- }
214
- }
215
-
216
- /**
217
- * @param {import('rollup').OutputOptions} options
218
- * @returns {import('rollup').OutputOptions}
219
- */
220
- const createLegacyOutput = (options = {}) => {
221
- return {
222
- ...options,
223
- format: 'system',
224
- entryFileNames: getLegacyOutputFileName(options.entryFileNames),
225
- chunkFileNames: getLegacyOutputFileName(options.chunkFileNames)
226
- }
227
- }
228
-
229
- const { rollupOptions } = config.build
230
- const { output } = rollupOptions
231
- if (Array.isArray(output)) {
232
- rollupOptions.output = [...output.map(createLegacyOutput), ...output]
233
- } else {
234
- rollupOptions.output = [createLegacyOutput(output), output || {}]
235
- }
236
- },
237
-
238
- renderChunk(raw, chunk, opts) {
239
- if (config.build.ssr) {
240
- return
241
- }
242
-
243
- if (!isLegacyChunk(chunk, opts)) {
244
- if (
245
- options.modernPolyfills &&
246
- !Array.isArray(options.modernPolyfills)
247
- ) {
248
- // analyze and record modern polyfills
249
- detectPolyfills(raw, { esmodules: true }, modernPolyfills)
250
- }
251
-
252
- const ms = new MagicString(raw)
253
-
254
- if (genDynamicFallback && chunk.isEntry) {
255
- ms.prepend(forceDynamicImportUsage)
256
- }
257
-
258
- if (raw.includes(legacyEnvVarMarker)) {
259
- const re = new RegExp(legacyEnvVarMarker, 'g')
260
- let match
261
- while ((match = re.exec(raw))) {
262
- ms.overwrite(
263
- match.index,
264
- match.index + legacyEnvVarMarker.length,
265
- `false`
266
- )
267
- }
268
- }
269
-
270
- if (config.build.sourcemap) {
271
- return {
272
- code: ms.toString(),
273
- map: ms.generateMap({ hires: true })
274
- }
275
- }
276
- return ms.toString()
277
- }
278
-
279
- if (!genLegacy) {
280
- return
281
- }
282
-
283
- // @ts-ignore avoid esbuild transform on legacy chunks since it produces
284
- // legacy-unsafe code - e.g. rewriting object properties into shorthands
285
- opts.__vite_skip_esbuild__ = true
286
-
287
- // @ts-ignore force terser for legacy chunks. This only takes effect if
288
- // minification isn't disabled, because that leaves out the terser plugin
289
- // entirely.
290
- opts.__vite_force_terser__ = true
291
-
292
- // @ts-ignore
293
- // In the `generateBundle` hook,
294
- // we'll delete the assets from the legacy bundle to avoid emitting duplicate assets.
295
- // But that's still a waste of computing resource.
296
- // So we add this flag to avoid emitting the asset in the first place whenever possible.
297
- opts.__vite_skip_asset_emit__ = true
298
-
299
- // @ts-ignore avoid emitting assets for legacy bundle
300
- const needPolyfills =
301
- options.polyfills !== false && !Array.isArray(options.polyfills)
302
-
303
- // transform the legacy chunk with @babel/preset-env
304
- const sourceMaps = !!config.build.sourcemap
305
- const { code, map } = loadBabel().transform(raw, {
306
- babelrc: false,
307
- configFile: false,
308
- compact: true,
309
- sourceMaps,
310
- inputSourceMap: sourceMaps && chunk.map,
311
- presets: [
312
- // forcing our plugin to run before preset-env by wrapping it in a
313
- // preset so we can catch the injected import statements...
314
- [
315
- () => ({
316
- plugins: [
317
- recordAndRemovePolyfillBabelPlugin(legacyPolyfills),
318
- replaceLegacyEnvBabelPlugin(),
319
- wrapIIFEBabelPlugin()
320
- ]
321
- })
322
- ],
323
- [
324
- 'env',
325
- {
326
- targets,
327
- modules: false,
328
- bugfixes: true,
329
- loose: false,
330
- useBuiltIns: needPolyfills ? 'usage' : false,
331
- corejs: needPolyfills
332
- ? {
333
- version: require('core-js/package.json').version,
334
- proposals: false
335
- }
336
- : undefined,
337
- shippedProposals: true,
338
- ignoreBrowserslistConfig: options.ignoreBrowserslistConfig
339
- }
340
- ]
341
- ]
342
- })
343
-
344
- return { code, map }
345
- },
346
-
347
- transformIndexHtml(html, { chunk }) {
348
- if (config.build.ssr) return
349
- if (!chunk) return
350
- if (chunk.fileName.includes('-legacy')) {
351
- // The legacy bundle is built first, and its index.html isn't actually
352
- // emitted. Here we simply record its corresponding legacy chunk.
353
- facadeToLegacyChunkMap.set(chunk.facadeModuleId, chunk.fileName)
354
- return
355
- }
356
-
357
- /**
358
- * @type {import('vite').HtmlTagDescriptor[]}
359
- */
360
- const tags = []
361
- const htmlFilename = chunk.facadeModuleId.replace(/\?.*$/, '')
362
-
363
- // 1. inject modern polyfills
364
- const modernPolyfillFilename = facadeToModernPolyfillMap.get(
365
- chunk.facadeModuleId
366
- )
367
- if (modernPolyfillFilename) {
368
- tags.push({
369
- tag: 'script',
370
- attrs: {
371
- type: 'module',
372
- src: `${config.base}${modernPolyfillFilename}`
373
- }
374
- })
375
- } else if (modernPolyfills.size) {
376
- throw new Error(
377
- `No corresponding modern polyfill chunk found for ${htmlFilename}`
378
- )
379
- }
380
-
381
- if (!genLegacy) {
382
- return { html, tags }
383
- }
384
-
385
- // 2. inject Safari 10 nomodule fix
386
- tags.push({
387
- tag: 'script',
388
- attrs: { nomodule: true },
389
- children: safari10NoModuleFix,
390
- injectTo: 'body'
391
- })
392
-
393
- // 3. inject legacy polyfills
394
- const legacyPolyfillFilename = facadeToLegacyPolyfillMap.get(
395
- chunk.facadeModuleId
396
- )
397
- if (legacyPolyfillFilename) {
398
- tags.push({
399
- tag: 'script',
400
- attrs: {
401
- nomodule: true,
402
- id: legacyPolyfillId,
403
- src: `${config.base}${legacyPolyfillFilename}`
404
- },
405
- injectTo: 'body'
406
- })
407
- } else if (legacyPolyfills.size) {
408
- throw new Error(
409
- `No corresponding legacy polyfill chunk found for ${htmlFilename}`
410
- )
411
- }
412
-
413
- // 4. inject legacy entry
414
- const legacyEntryFilename = facadeToLegacyChunkMap.get(
415
- chunk.facadeModuleId
416
- )
417
- if (legacyEntryFilename) {
418
- tags.push({
419
- tag: 'script',
420
- attrs: {
421
- nomodule: true,
422
- // we set the entry path on the element as an attribute so that the
423
- // script content will stay consistent - which allows using a constant
424
- // hash value for CSP.
425
- id: legacyEntryId,
426
- 'data-src': config.base + legacyEntryFilename
427
- },
428
- children: systemJSInlineCode,
429
- injectTo: 'body'
430
- })
431
- } else {
432
- throw new Error(
433
- `No corresponding legacy entry chunk found for ${htmlFilename}`
434
- )
435
- }
436
-
437
- // 5. inject dynamic import fallback entry
438
- if (genDynamicFallback && legacyPolyfillFilename && legacyEntryFilename) {
439
- tags.push({
440
- tag: 'script',
441
- attrs: { type: 'module' },
442
- children: detectDynamicImportCode,
443
- injectTo: 'head'
444
- })
445
- tags.push({
446
- tag: 'script',
447
- attrs: { type: 'module' },
448
- children: dynamicFallbackInlineCode,
449
- injectTo: 'head'
450
- })
451
- }
452
-
453
- return {
454
- html,
455
- tags
456
- }
457
- },
458
-
459
- generateBundle(opts, bundle) {
460
- if (config.build.ssr) {
461
- return
462
- }
463
-
464
- if (isLegacyBundle(bundle, opts)) {
465
- // avoid emitting duplicate assets
466
- for (const name in bundle) {
467
- if (bundle[name].type === 'asset') {
468
- delete bundle[name]
469
- }
470
- }
471
- }
472
- }
473
- }
474
-
475
- let envInjectionFailed = false
476
- /**
477
- * @type {import('vite').Plugin}
478
- */
479
- const legacyEnvPlugin = {
480
- name: 'vite:legacy-env',
481
-
482
- config(config, env) {
483
- if (env) {
484
- return {
485
- define: {
486
- 'import.meta.env.LEGACY':
487
- env.command === 'serve' || config.build.ssr
488
- ? false
489
- : legacyEnvVarMarker
490
- }
491
- }
492
- } else {
493
- envInjectionFailed = true
494
- }
495
- },
496
-
497
- configResolved(config) {
498
- if (envInjectionFailed) {
499
- config.logger.warn(
500
- `[@vitejs/plugin-legacy] import.meta.env.LEGACY was not injected due ` +
501
- `to incompatible vite version (requires vite@^2.0.0-beta.69).`
502
- )
503
- }
504
- }
505
- }
506
-
507
- return [
508
- legacyConfigPlugin,
509
- legacyGenerateBundlePlugin,
510
- legacyPostPlugin,
511
- legacyEnvPlugin
512
- ]
513
- }
514
-
515
- /**
516
- * @param {string} code
517
- * @param {any} targets
518
- * @param {Set<string>} list
519
- */
520
- function detectPolyfills(code, targets, list) {
521
- const { ast } = loadBabel().transform(code, {
522
- ast: true,
523
- babelrc: false,
524
- configFile: false,
525
- presets: [
526
- [
527
- 'env',
528
- {
529
- targets,
530
- modules: false,
531
- useBuiltIns: 'usage',
532
- corejs: { version: 3, proposals: false },
533
- shippedProposals: true,
534
- ignoreBrowserslistConfig: true
535
- }
536
- ]
537
- ]
538
- })
539
- for (const node of ast.program.body) {
540
- if (node.type === 'ImportDeclaration') {
541
- const source = node.source.value
542
- if (
543
- source.startsWith('core-js/') ||
544
- source.startsWith('regenerator-runtime/')
545
- ) {
546
- list.add(source)
547
- }
548
- }
549
- }
550
- }
551
-
552
- /**
553
- * @param {string} name
554
- * @param {Set<string>} imports
555
- * @param {import('rollup').OutputBundle} bundle
556
- * @param {Map<string, string>} facadeToChunkMap
557
- * @param {import('vite').BuildOptions} buildOptions
558
- */
559
- async function buildPolyfillChunk(
560
- name,
561
- imports,
562
- bundle,
563
- facadeToChunkMap,
564
- buildOptions,
565
- externalSystemJS
566
- ) {
567
- let { minify, assetsDir } = buildOptions
568
- minify = minify ? 'terser' : false
569
- const res = await build({
570
- // so that everything is resolved from here
571
- root: __dirname,
572
- configFile: false,
573
- logLevel: 'error',
574
- plugins: [polyfillsPlugin(imports, externalSystemJS)],
575
- build: {
576
- write: false,
577
- target: false,
578
- minify,
579
- assetsDir,
580
- rollupOptions: {
581
- input: {
582
- [name]: polyfillId
583
- },
584
- output: {
585
- format: name.includes('legacy') ? 'iife' : 'es',
586
- manualChunks: undefined
587
- }
588
- }
589
- }
590
- })
591
- const _polyfillChunk = Array.isArray(res) ? res[0] : res
592
- if (!('output' in _polyfillChunk)) return
593
- const polyfillChunk = _polyfillChunk.output[0]
594
-
595
- // associate the polyfill chunk to every entry chunk so that we can retrieve
596
- // the polyfill filename in index html transform
597
- for (const key in bundle) {
598
- const chunk = bundle[key]
599
- if (chunk.type === 'chunk' && chunk.facadeModuleId) {
600
- facadeToChunkMap.set(chunk.facadeModuleId, polyfillChunk.fileName)
601
- }
602
- }
603
-
604
- // add the chunk to the bundle
605
- bundle[polyfillChunk.name] = polyfillChunk
606
- }
607
-
608
- const polyfillId = '\0vite/legacy-polyfills'
609
-
610
- /**
611
- * @param {Set<string>} imports
612
- * @return {import('rollup').Plugin}
613
- */
614
- function polyfillsPlugin(imports, externalSystemJS) {
615
- return {
616
- name: 'vite:legacy-polyfills',
617
- resolveId(id) {
618
- if (id === polyfillId) {
619
- return id
620
- }
621
- },
622
- load(id) {
623
- if (id === polyfillId) {
624
- return (
625
- [...imports].map((i) => `import "${i}";`).join('') +
626
- (externalSystemJS ? '' : `import "systemjs/dist/s.min.js";`)
627
- )
628
- }
629
- }
630
- }
631
- }
632
-
633
- /**
634
- * @param {import('rollup').RenderedChunk} chunk
635
- * @param {import('rollup').NormalizedOutputOptions} options
636
- */
637
- function isLegacyChunk(chunk, options) {
638
- return options.format === 'system' && chunk.fileName.includes('-legacy')
639
- }
640
-
641
- /**
642
- * @param {import('rollup').OutputBundle} bundle
643
- * @param {import('rollup').NormalizedOutputOptions} options
644
- */
645
- function isLegacyBundle(bundle, options) {
646
- if (options.format === 'system') {
647
- const entryChunk = Object.values(bundle).find(
648
- (output) => output.type === 'chunk' && output.isEntry
649
- )
650
-
651
- return !!entryChunk && entryChunk.fileName.includes('-legacy')
652
- }
653
-
654
- return false
655
- }
656
-
657
- /**
658
- * @param {Set<string>} polyfills
659
- */
660
- function recordAndRemovePolyfillBabelPlugin(polyfills) {
661
- return ({ types: t }) => ({
662
- name: 'vite-remove-polyfill-import',
663
- post({ path }) {
664
- path.get('body').forEach((p) => {
665
- if (t.isImportDeclaration(p)) {
666
- polyfills.add(p.node.source.value)
667
- p.remove()
668
- }
669
- })
670
- }
671
- })
672
- }
673
-
674
- function replaceLegacyEnvBabelPlugin() {
675
- return ({ types: t }) => ({
676
- name: 'vite-replace-env-legacy',
677
- visitor: {
678
- Identifier(path) {
679
- if (path.node.name === legacyEnvVarMarker) {
680
- path.replaceWith(t.booleanLiteral(true))
681
- }
682
- }
683
- }
684
- })
685
- }
686
-
687
- function wrapIIFEBabelPlugin() {
688
- return ({ types: t, template }) => {
689
- const buildIIFE = template(';(function(){%%body%%})();')
690
-
691
- return {
692
- name: 'vite-wrap-iife',
693
- post({ path }) {
694
- if (!this.isWrapped) {
695
- this.isWrapped = true
696
- path.replaceWith(t.program(buildIIFE({ body: path.node.body })))
697
- }
698
- }
699
- }
700
- }
701
- }
702
-
703
- module.exports = viteLegacyPlugin
704
-
705
- viteLegacyPlugin.default = viteLegacyPlugin
706
-
707
- viteLegacyPlugin.cspHashes = [
708
- createHash('sha256').update(safari10NoModuleFix).digest('base64'),
709
- createHash('sha256').update(systemJSInlineCode).digest('base64'),
710
- createHash('sha256').update(detectDynamicImportCode).digest('base64'),
711
- createHash('sha256').update(dynamicFallbackInlineCode).digest('base64')
712
- ]