From fe6ed562e93fcf96a86ccda8a0d70b8b8bcff460 Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 26 Oct 2022 23:58:21 +0800 Subject: [PATCH 1/2] Improve Astro libraries config handling --- .changeset/witty-melons-heal.md | 5 + packages/astro/package.json | 1 + packages/astro/src/core/create-vite.ts | 151 +++++-------------------- pnpm-lock.yaml | 14 +++ 4 files changed, 51 insertions(+), 120 deletions(-) create mode 100644 .changeset/witty-melons-heal.md diff --git a/.changeset/witty-melons-heal.md b/.changeset/witty-melons-heal.md new file mode 100644 index 000000000000..27202d2c5967 --- /dev/null +++ b/.changeset/witty-melons-heal.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Improve Astro libraries config handling diff --git a/packages/astro/package.json b/packages/astro/package.json index 331ef6b27d7b..90b9a0284245 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -158,6 +158,7 @@ "unist-util-visit": "^4.1.0", "vfile": "^5.3.2", "vite": "~3.1.3", + "vitefu": "^0.0.1", "yargs-parser": "^21.0.1", "zod": "^3.17.3" }, diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts index fc39e3bdbc59..63e780961712 100644 --- a/packages/astro/src/core/create-vite.ts +++ b/packages/astro/src/core/create-vite.ts @@ -1,11 +1,9 @@ import type { AstroSettings } from '../@types/astro'; import type { LogOptions } from './logger/core'; -import fs from 'fs'; -import { createRequire } from 'module'; -import path from 'path'; import { fileURLToPath } from 'url'; import * as vite from 'vite'; +import { crawlFrameworkPkgs } from 'vitefu'; import astroPostprocessVitePlugin from '../vite-plugin-astro-postprocess/index.js'; import astroViteServerPlugin from '../vite-plugin-astro-server/index.js'; import astroVitePlugin from '../vite-plugin-astro/index.js'; @@ -58,7 +56,31 @@ export async function createVite( commandConfig: vite.InlineConfig, { settings, logging, mode }: CreateViteOptions ): Promise { - const thirdPartyAstroPackages = await getAstroPackages(settings); + const astroPkgsConfig = await crawlFrameworkPkgs({ + root: fileURLToPath(settings.config.root), + isBuild: mode === 'build', + isFrameworkPkgByJson(pkgJson) { + return ( + // Attempt: package relies on `astro`. ✅ Definitely an Astro package + pkgJson.peerDependencies?.astro || + pkgJson.dependencies?.astro || + // Attempt: package is tagged with `astro` or `astro-component`. ✅ Likely a community package + pkgJson.keywords?.includes('astro') || + pkgJson.keywords?.includes('astro-component') || + // Attempt: package is named `astro-something` or `@scope/astro-something`. ✅ Likely a community package + /^(@[^\/]+\/)?astro\-/.test(pkgJson.name) + ); + }, + isFrameworkPkgByName(pkgName) { + const isNotAstroPkg = isCommonNotAstro(pkgName); + if (isNotAstroPkg) { + return false; + } else { + return undefined; + } + }, + }); + // Start with the Vite configuration that Astro core needs const commonConfig: vite.InlineConfig = { cacheDir: fileURLToPath(new URL('./node_modules/.vite/', settings.config.root)), // using local caches allows Astro to be used in monorepos, etc. @@ -126,11 +148,14 @@ export async function createVite( conditions: ['astro'], }, ssr: { - noExternal: [...getSsrNoExternalDeps(settings.config.root), ...thirdPartyAstroPackages], + noExternal: [ + ...getSsrNoExternalDeps(settings.config.root), + ...astroPkgsConfig.ssr.noExternal, + ], // shiki is imported by Code.astro, which is no-externalized (processed by Vite). // However, shiki's deps are in CJS and trips up Vite's dev SSR transform, externalize // shiki to load it with node instead. - external: mode === 'dev' ? ['shiki'] : [], + external: [...(mode === 'dev' ? ['shiki'] : []), ...astroPkgsConfig.ssr.external], }, }; @@ -174,120 +199,6 @@ function sortPlugins(pluginOptions: vite.PluginOption[]) { pluginOptions.splice(jsxPluginIndex, 0, mdxPlugin); } -// Scans `projectRoot` for third-party Astro packages that could export an `.astro` file -// `.astro` files need to be built by Vite, so these should use `noExternal` -async function getAstroPackages(settings: AstroSettings): Promise { - const { astroPackages } = new DependencyWalker(settings.config.root); - return astroPackages; -} - -/** - * Recursively walk a project’s dependency tree trying to find Astro packages. - * - If the current node is an Astro package, we continue walking its child dependencies. - * - If the current node is not an Astro package, we bail out of walking that branch. - * This assumes it is unlikely for Astro packages to be dependencies of packages that aren’t - * themselves also Astro packages. - */ -class DependencyWalker { - private readonly require: NodeRequire; - private readonly astroDeps = new Set(); - private readonly nonAstroDeps = new Set(); - - constructor(root: URL) { - const pkgUrl = new URL('./package.json', root); - this.require = createRequire(pkgUrl); - const pkgPath = fileURLToPath(pkgUrl); - if (!fs.existsSync(pkgPath)) return; - - const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); - const deps = [ - ...Object.keys(pkg.dependencies || {}), - ...Object.keys(pkg.devDependencies || {}), - ]; - - this.scanDependencies(deps); - } - - /** The dependencies we determined were likely to include `.astro` files. */ - public get astroPackages(): string[] { - return Array.from(this.astroDeps); - } - - private seen(dep: string): boolean { - return this.astroDeps.has(dep) || this.nonAstroDeps.has(dep); - } - - /** Try to load a directory’s `package.json` file from the filesystem. */ - private readPkgJSON(dir: string): PkgJSON | void { - try { - const filePath = path.join(dir, 'package.json'); - return JSON.parse(fs.readFileSync(filePath, 'utf-8')); - } catch (e) {} - } - - /** Try to resolve a dependency’s `package.json` even if not a package export. */ - private resolvePkgJSON(dep: string): PkgJSON | void { - try { - const pkgJson: PkgJSON = this.require(dep + '/package.json'); - return pkgJson; - } catch (e) { - // Most likely error is that the dependency doesn’t include `package.json` in its package `exports`. - try { - // Walk up from default export until we find `package.json` with name === dep. - let dir = path.dirname(this.require.resolve(dep)); - while (dir) { - const pkgJSON = this.readPkgJSON(dir); - if (pkgJSON && pkgJSON.name === dep) return pkgJSON; - - const parentDir = path.dirname(dir); - if (parentDir === dir) break; - - dir = parentDir; - } - } catch { - // Give up! Who knows where the `package.json` is… - } - } - } - - private scanDependencies(deps: string[]): void { - const newDeps: string[] = []; - for (const dep of deps) { - // Attempt: package is common and not Astro. ❌ Skip these for perf - if (isCommonNotAstro(dep)) { - this.nonAstroDeps.add(dep); - continue; - } - - const pkgJson = this.resolvePkgJSON(dep); - if (!pkgJson) { - this.nonAstroDeps.add(dep); - continue; - } - const { dependencies = {}, peerDependencies = {}, keywords = [] } = pkgJson; - - if ( - // Attempt: package relies on `astro`. ✅ Definitely an Astro package - peerDependencies.astro || - dependencies.astro || - // Attempt: package is tagged with `astro` or `astro-component`. ✅ Likely a community package - keywords.includes('astro') || - keywords.includes('astro-component') || - // Attempt: package is named `astro-something` or `@scope/astro-something`. ✅ Likely a community package - /^(@[^\/]+\/)?astro\-/.test(dep) - ) { - this.astroDeps.add(dep); - // Collect any dependencies of this Astro package we haven’t seen yet. - const unknownDependencies = Object.keys(dependencies).filter((d) => !this.seen(d)); - newDeps.push(...unknownDependencies); - } else { - this.nonAstroDeps.add(dep); - } - } - if (newDeps.length) this.scanDependencies(newDeps); - } -} - const COMMON_DEPENDENCIES_NOT_ASTRO = [ 'autoprefixer', 'react', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8a5924de78d5..14ea9765a8b8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -455,6 +455,7 @@ importers: unist-util-visit: ^4.1.0 vfile: ^5.3.2 vite: ~3.1.3 + vitefu: ^0.0.1 yargs-parser: ^21.0.1 zod: ^3.17.3 dependencies: @@ -517,6 +518,7 @@ importers: unist-util-visit: 4.1.1 vfile: 5.3.5 vite: 3.1.8_sass@1.55.0 + vitefu: 0.0.1_vite@3.1.8 yargs-parser: 21.1.1 zod: 3.19.1 devDependencies: @@ -18014,6 +18016,18 @@ packages: fsevents: 2.3.2 dev: false + /vitefu/0.0.1_vite@3.1.8: + resolution: {integrity: sha512-lOPcUgjTPi7hs1nAIgv8wOkIlMiNMzuWe8Ts7mM9IsH0OZkNjv24CZ0XX0ET/nS6CP8+Lij8j2ZpiLe7bVKVVQ==} + peerDependencies: + vite: ^3.0.0 + peerDependenciesMeta: + vite: + optional: true + dependencies: + import-meta-resolve: 2.1.0 + vite: 3.1.8_sass@1.55.0 + dev: false + /vitest/0.20.3: resolution: {integrity: sha512-cXMjTbZxBBUUuIF3PUzEGPLJWtIMeURBDXVxckSHpk7xss4JxkiiWh5cnIlfGyfJne2Ii3QpbiRuFL5dMJtljw==} engines: {node: '>=v14.16.0'} From 256e48b97377d3acdcd6e61205a49610d8f76d4b Mon Sep 17 00:00:00 2001 From: bluwy Date: Thu, 27 Oct 2022 01:52:02 +0800 Subject: [PATCH 2/2] Upgrade vitefu --- packages/astro/package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/astro/package.json b/packages/astro/package.json index 90b9a0284245..6ebfb9bab8e4 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -158,7 +158,7 @@ "unist-util-visit": "^4.1.0", "vfile": "^5.3.2", "vite": "~3.1.3", - "vitefu": "^0.0.1", + "vitefu": "^0.1.0", "yargs-parser": "^21.0.1", "zod": "^3.17.3" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 14ea9765a8b8..4ef405d6773e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -455,7 +455,7 @@ importers: unist-util-visit: ^4.1.0 vfile: ^5.3.2 vite: ~3.1.3 - vitefu: ^0.0.1 + vitefu: ^0.1.0 yargs-parser: ^21.0.1 zod: ^3.17.3 dependencies: @@ -518,7 +518,7 @@ importers: unist-util-visit: 4.1.1 vfile: 5.3.5 vite: 3.1.8_sass@1.55.0 - vitefu: 0.0.1_vite@3.1.8 + vitefu: 0.1.0_vite@3.1.8 yargs-parser: 21.1.1 zod: 3.19.1 devDependencies: @@ -18016,8 +18016,8 @@ packages: fsevents: 2.3.2 dev: false - /vitefu/0.0.1_vite@3.1.8: - resolution: {integrity: sha512-lOPcUgjTPi7hs1nAIgv8wOkIlMiNMzuWe8Ts7mM9IsH0OZkNjv24CZ0XX0ET/nS6CP8+Lij8j2ZpiLe7bVKVVQ==} + /vitefu/0.1.0_vite@3.1.8: + resolution: {integrity: sha512-5MQSHP9yr0HIve8q4XNb7QXfO1P4tzZDZP99qH0FM5ClcwYddeGXRDQ4TQYRUeXLjZ+vLecirHtGNpwFFUF7sw==} peerDependencies: vite: ^3.0.0 peerDependenciesMeta: