Skip to content

Commit

Permalink
feat: add option to output only legacy builds
Browse files Browse the repository at this point in the history
  • Loading branch information
k-yle committed Sep 8, 2023
1 parent d6ed84f commit 1b346d5
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 37 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ export default {

Defaults to `false`. Enabling this option will exclude `systemjs/dist/s.min.js` inside polyfills-legacy chunk.

### `renderModernChunks`

- **Type:** `boolean`
- **Default:** `true`

Set to `false` to only output the legacy bundles that support all target browsers.

## Browsers that supports ESM but does not support widely-available features

The legacy plugin offers a way to use widely-available features natively in the modern build, while falling back to the legacy build in browsers with native ESM but without those features supported (e.g. Legacy Edge). This feature works by injecting a runtime check and loading the legacy bundle with SystemJs runtime if needed. There are the following drawbacks:
Expand Down
96 changes: 59 additions & 37 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,12 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] {
let targets: Options['targets']

const genLegacy = options.renderLegacyChunks !== false
const genModern = options.renderModernChunks !== false
if (!genLegacy && !genModern) {
throw new Error(
'`renderLegacyChunks` and `renderModernChunks` cannot be both false',
)
}

const debugFlags = (process.env.DEBUG ?? '').split(',')
const isDebug
Expand All @@ -145,7 +151,7 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] {
const modernPolyfills = new Set<string>()
const legacyPolyfills = new Set<string>()

if (Array.isArray(options.modernPolyfills)) {
if (Array.isArray(options.modernPolyfills) && genModern) {
options.modernPolyfills.forEach((i) => {
modernPolyfills.add(
i.includes('/') ? `core-js/${i}` : `core-js/modules/${i}.js`,
Expand Down Expand Up @@ -360,9 +366,15 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] {
const { rollupOptions } = resolvedConfig.build
const { output } = rollupOptions
if (Array.isArray(output)) {
rollupOptions.output = [...output.map(createLegacyOutput), ...output]
rollupOptions.output = [
...output.map(createLegacyOutput),
...(genModern ? output : []),
]
} else {
rollupOptions.output = [createLegacyOutput(output), output ?? {}]
rollupOptions.output = [
createLegacyOutput(output),
...(genModern ? [output || {}] : []),
]
}
},

Expand All @@ -374,7 +386,8 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] {
if (!isLegacyChunk(chunk, opts)) {
if (
options.modernPolyfills
&& !Array.isArray(options.modernPolyfills)
&& !Array.isArray(options.modernPolyfills) &&
genModern
) {
// analyze and record modern polyfills
await detectPolyfills(raw, 'supports es6-module', modernPolyfills)
Expand Down Expand Up @@ -497,50 +510,59 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] {
if (resolvedConfig.build.ssr) return
if (!chunk) return
if (chunk.fileName.includes('-legacy')) {
// The legacy bundle is built first, and its index.html isn't actually
// emitted. Here we simply record its corresponding legacy chunk.
// The legacy bundle is built first, and its index.html isn't actually emitted if
// modern bundle will be generated. Here we simply record its corresponding legacy chunk.
facadeToLegacyChunkMap.set(chunk.facadeModuleId, chunk.fileName)
return
if (genModern) {
return
}
}
if (!genModern) {
html = html.replace(/<script type="module".*?<\/script>/g, '')
}

const tags: HtmlTagDescriptor[] = []
const htmlFilename = chunk.facadeModuleId?.replace(/\?.*$/, '')

// 1. inject modern polyfills
const modernPolyfillFilename = facadeToModernPolyfillMap.get(
chunk.facadeModuleId,
)

if (modernPolyfillFilename) {
tags.push({
tag: 'script',
attrs: {
type: 'module',
crossorigin: true,
src: toAssetPathFromHtml(
modernPolyfillFilename,
chunk.facadeModuleId!,
resolvedConfig,
),
},
})
} else if (modernPolyfills.size) {
throw new Error(
`No corresponding modern polyfill chunk found for ${htmlFilename}`,
if (genModern) {
const modernPolyfillFilename = facadeToModernPolyfillMap.get(
chunk.facadeModuleId,
)

if (modernPolyfillFilename) {
tags.push({
tag: 'script',
attrs: {
type: 'module',
crossorigin: true,
src: toAssetPathFromHtml(
modernPolyfillFilename,
chunk.facadeModuleId!,
resolvedConfig,
),
},
})
} else if (modernPolyfills.size) {
throw new Error(
`No corresponding modern polyfill chunk found for ${htmlFilename}`,
)
}
}

if (!genLegacy) {
return { html, tags }
}

// 2. inject Safari 10 nomodule fix
tags.push({
tag: 'script',
attrs: { nomodule: true },
children: safari10NoModuleFix,
injectTo: 'body',
})
if (genModern) {
tags.push({
tag: 'script',
attrs: { nomodule: true },
children: safari10NoModuleFix,
injectTo: 'body',
})
}

// 3. inject legacy polyfills
const legacyPolyfillFilename = facadeToLegacyPolyfillMap.get(
Expand All @@ -550,7 +572,7 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] {
tags.push({
tag: 'script',
attrs: {
nomodule: true,
nomodule: genModern,
crossorigin: true,
id: legacyPolyfillId,
src: toAssetPathFromHtml(
Expand All @@ -576,7 +598,7 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] {
tags.push({
tag: 'script',
attrs: {
nomodule: true,
nomodule: genModern,
crossorigin: true,
// we set the entry path on the element as an attribute so that the
// script content will stay consistent - which allows using a constant
Expand All @@ -598,7 +620,7 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] {
}

// 5. inject dynamic import fallback entry
if (/* genLegacy && */legacyPolyfillFilename && legacyEntryFilename) {
if (legacyPolyfillFilename && legacyEntryFilename && genModern) {
tags.push({
tag: 'script',
attrs: { type: 'module' },
Expand All @@ -624,7 +646,7 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] {
return
}

if (isLegacyBundle(bundle, opts)) {
if (isLegacyBundle(bundle, opts) && genModern) {
// avoid emitting duplicate assets
for (const name of Object.keys(bundle)) {
if (bundle[name].type === 'asset' && !/.+\.map$/.test(name)) {
Expand Down
4 changes: 4 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@ export interface Options {
* default: false
*/
externalSystemJS?: boolean,
/**
* default: true
*/
renderModernChunks?: boolean
}

0 comments on commit 1b346d5

Please sign in to comment.