Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add option to output only legacy builds #3

Merged
merged 1 commit into from
Sep 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}