diff --git a/package.json b/package.json index d0d7324..1ae4d81 100644 --- a/package.json +++ b/package.json @@ -38,11 +38,8 @@ "dist/" ], "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.27.1", - "@babel/plugin-transform-react-jsx-development": "^7.27.1", "@prefresh/vite": "^2.4.11", "@rollup/pluginutils": "^5.0.0", - "babel-plugin-transform-hook-names": "^1.0.2", "debug": "^4.4.3", "magic-string": "^0.30.21", "picocolors": "^1.1.1", @@ -51,10 +48,35 @@ }, "peerDependencies": { "@babel/core": "7.x", + "@babel/parser": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-react-jsx-development": "^7.0.0", + "babel-plugin-transform-hook-names": "^1.0.0", "vite": "2.x || 3.x || 4.x || 5.x || 6.x || 7.x || 8.x" }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@babel/parser": { + "optional": true + }, + "@babel/plugin-transform-react-jsx": { + "optional": true + }, + "@babel/plugin-transform-react-jsx-development": { + "optional": true + }, + "babel-plugin-transform-hook-names": { + "optional": true + } + }, "devDependencies": { "@babel/core": "^7.28.5", + "@babel/parser": "^7.28.5", + "@babel/plugin-transform-react-jsx": "^7.27.1", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "babel-plugin-transform-hook-names": "^1.0.2", "@types/babel__core": "^7.20.5", "@types/debug": "^4.1.12", "@types/estree": "^0.0.50", diff --git a/src/index.ts b/src/index.ts index 44a91ab..4e2b93c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,13 +8,43 @@ import { preactDevtoolsPlugin } from "./devtools.js"; import { transformHookNamesPlugin } from "./transform-hook-names.js"; import { createFilter, parseId } from "./utils.js"; import { vitePrerenderPlugin } from "vite-prerender-plugin"; -import { transformAsync } from "@babel/core"; -// @ts-ignore package doesn't ship with declaration files -import babelReactJsx from "@babel/plugin-transform-react-jsx"; -// @ts-ignore package doesn't ship with declaration files -import babelReactJsxDev from "@babel/plugin-transform-react-jsx-development"; -// @ts-ignore package doesn't ship with declaration files -import babelHookNames from "babel-plugin-transform-hook-names"; + +type BabelDeps = { + transformAsync: typeof import("@babel/core").transformAsync; + babelReactJsx: any; + babelReactJsxDev: any; + babelHookNames: any; +}; + +let babelDepsPromise: Promise | null = null; + +function loadBabelDeps(): Promise { + return (babelDepsPromise ||= Promise.all([ + import("@babel/core"), + // @ts-ignore package doesn't ship with declaration files + import("@babel/plugin-transform-react-jsx"), + // @ts-ignore package doesn't ship with declaration files + import("@babel/plugin-transform-react-jsx-development"), + // @ts-ignore package doesn't ship with declaration files + import("babel-plugin-transform-hook-names"), + ]) + .then(([core, jsx, jsxDev, hookNames]) => ({ + transformAsync: core.transformAsync, + babelReactJsx: (jsx as any).default ?? jsx, + babelReactJsxDev: (jsxDev as any).default ?? jsxDev, + babelHookNames: (hookNames as any).default ?? hookNames, + })) + .catch(err => { + babelDepsPromise = null; + throw new Error( + "@preact/preset-vite: the `babel` option requires `@babel/core`, " + + "`@babel/plugin-transform-react-jsx`, " + + "`@babel/plugin-transform-react-jsx-development`, and " + + "`babel-plugin-transform-hook-names` to be installed.\n" + + `Underlying error: ${err instanceof Error ? err.message : err}`, + ); + })); +} export type BabelOptions = Omit< TransformOptions, @@ -237,6 +267,9 @@ function preactPlugin({ if (!useBabel || !shouldTransform(id)) return; + const { transformAsync, babelReactJsx, babelReactJsxDev, babelHookNames } = + await loadBabelDeps(); + const parserPlugins = [ ...baseParserOptions, "classProperties",