From cb31df936b88858eae6c4c4b7d0e7e5ef68f0212 Mon Sep 17 00:00:00 2001 From: Dominic Saadi Date: Fri, 28 Jul 2023 00:34:05 -0700 Subject: [PATCH] feat(vite): add plugin to remove modules from the bundle (#8973) Co-authored-by: Tobbe Lundberg Co-authored-by: Daniel Choudhury --- packages/vite/src/index.ts | 9 +++- .../__tests__/remove-from-bundle.test.mts | 31 +++++++++++++ .../{ => plugins}/vite-plugin-jsx-loader.ts | 2 +- .../plugins/vite-plugin-remove-from-bundle.ts | 45 +++++++++++++++++++ 4 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 packages/vite/src/plugins/__tests__/remove-from-bundle.test.mts rename packages/vite/src/{ => plugins}/vite-plugin-jsx-loader.ts (90%) create mode 100644 packages/vite/src/plugins/vite-plugin-remove-from-bundle.ts diff --git a/packages/vite/src/index.ts b/packages/vite/src/index.ts index 660084d318a5..d6ea00ef475b 100644 --- a/packages/vite/src/index.ts +++ b/packages/vite/src/index.ts @@ -8,7 +8,8 @@ import { normalizePath } from 'vite' import { getWebSideDefaultBabelConfig } from '@redwoodjs/internal/dist/build/babel/web' import { getConfig, getPaths } from '@redwoodjs/project-config' -import { handleJsAsJsx } from './vite-plugin-jsx-loader' +import handleJsAsJsx from './plugins/vite-plugin-jsx-loader' +import removeFromBundle from './plugins/vite-plugin-remove-from-bundle' /** * Pre-configured vite plugin, with required config for Redwood apps. @@ -260,6 +261,12 @@ export default function redwoodPluginVite(): PluginOption[] { }, // ----------------- handleJsAsJsx(), + // Remove the splash-page from the bundle. + removeFromBundle([ + { + id: /@redwoodjs\/router\/dist\/splash-page/, + }, + ]), react({ babel: { ...getWebSideDefaultBabelConfig({ diff --git a/packages/vite/src/plugins/__tests__/remove-from-bundle.test.mts b/packages/vite/src/plugins/__tests__/remove-from-bundle.test.mts new file mode 100644 index 000000000000..8147fe6c26db --- /dev/null +++ b/packages/vite/src/plugins/__tests__/remove-from-bundle.test.mts @@ -0,0 +1,31 @@ +import assert from 'node:assert/strict' +import { describe, it } from 'node:test' + +import * as vitePluginRemoveFromBundle from '../vite-plugin-remove-from-bundle.js' + +// @ts-expect-error We have to write it this way to appease node:test, but TS doesn't seem to like it. +// node:test needs to be configured correctly, I imagine. +const { excludeOnMatch } = vitePluginRemoveFromBundle.default + +describe('excludeModule', () => { + it('should return true if idToExclude matches id', () => { + const loadOutput = excludeOnMatch([{ + id: /router\/dist\/splash-page/, + }], + '/Users/dac09/Experiments/splash-page-null-loader/node_modules/@redwoodjs/router/dist/splash-page.js?commonjs-exports', + ) + + assert.notStrictEqual(loadOutput, { + code: 'module.exports = null' + }) + }) + + it("should return false if idToExclude doesn't match id", () => { + const loadOutput = excludeOnMatch([{ + id: /bazinga-page/, + }], + '/Users/dac09/Experiments/splash-page-null-loader/node_modules/@redwoodjs/router/dist/params.js') + + assert.equal(loadOutput, null) + }) +}) diff --git a/packages/vite/src/vite-plugin-jsx-loader.ts b/packages/vite/src/plugins/vite-plugin-jsx-loader.ts similarity index 90% rename from packages/vite/src/vite-plugin-jsx-loader.ts rename to packages/vite/src/plugins/vite-plugin-jsx-loader.ts index bbcf9cbe72cd..3349e4f6a712 100644 --- a/packages/vite/src/vite-plugin-jsx-loader.ts +++ b/packages/vite/src/plugins/vite-plugin-jsx-loader.ts @@ -5,7 +5,7 @@ import { PluginOption, transformWithEsbuild } from 'vite' * This is a vite plugin to load and transform JS files as JSX. * */ -export function handleJsAsJsx(): PluginOption { +export default function handleJsAsJsx(): PluginOption { return { name: 'transform-js-files-as-jsx', async transform(code: string, id: string) { diff --git a/packages/vite/src/plugins/vite-plugin-remove-from-bundle.ts b/packages/vite/src/plugins/vite-plugin-remove-from-bundle.ts new file mode 100644 index 000000000000..3cfd18d8a138 --- /dev/null +++ b/packages/vite/src/plugins/vite-plugin-remove-from-bundle.ts @@ -0,0 +1,45 @@ +import type { PluginOption } from 'vite' + +type ModulesToExclude = Array<{ id: RegExp }> + +/** + * + * This is a vite plugin to remove modules from the bundle. + * + * Only applies on build, not on dev. + * + */ +export default function removeFromBundle( + modulesToExclude: ModulesToExclude +): PluginOption { + const isMissingIdToExclude = modulesToExclude.some( + (module) => module.id === undefined + ) + + if (isMissingIdToExclude) { + throw new Error('You must specify an id to exclude') + } + + return { + name: 'remove-from-bundle', + apply: 'build', // <-- @MARK important + load: (id) => { + return excludeOnMatch(modulesToExclude, id) + }, + } +} + +// Currently configured for CJS only. +const EMPTY_MODULE = { + code: `module.exports = null`, +} + +export function excludeOnMatch(modulesToExclude: ModulesToExclude, id: string) { + if (modulesToExclude.some((module) => module.id.test(id))) { + // Return an empty module + return EMPTY_MODULE + } + + // Fallback to regular loaders + return null +}