From 1ab505855f9942659e3d23cb1ac668f04b98889d Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Thu, 17 Nov 2022 10:32:59 -0500 Subject: [PATCH] Fix regression with loading .ts in .mjs config (#5431) * Fix regression with loading .ts in .mjs config * Account for directories --- .changeset/purple-tips-flash.md | 5 +++ packages/astro/src/core/config/vite-load.ts | 21 ++++++---- packages/astro/src/core/create-vite.ts | 2 +- .../src/vite-plugin-load-fallback/index.ts | 30 +++++++++----- .../astro/test/units/config/format.test.js | 41 +++++++++++++++++++ 5 files changed, 80 insertions(+), 19 deletions(-) create mode 100644 .changeset/purple-tips-flash.md create mode 100644 packages/astro/test/units/config/format.test.js diff --git a/.changeset/purple-tips-flash.md b/.changeset/purple-tips-flash.md new file mode 100644 index 0000000000..9d706cfbc5 --- /dev/null +++ b/.changeset/purple-tips-flash.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix regression with loading .ts in .mjs config diff --git a/packages/astro/src/core/config/vite-load.ts b/packages/astro/src/core/config/vite-load.ts index 7946015a5a..a864c784fd 100644 --- a/packages/astro/src/core/config/vite-load.ts +++ b/packages/astro/src/core/config/vite-load.ts @@ -3,6 +3,7 @@ import npath from 'path'; import { pathToFileURL } from 'url'; import * as vite from 'vite'; import { AstroError, AstroErrorData } from '../errors/index.js'; +import loadFallbackPlugin from '../../vite-plugin-load-fallback/index.js'; // Fallback for legacy import load from '@proload/core'; @@ -15,7 +16,7 @@ export interface ViteLoader { viteServer: vite.ViteDevServer; } -async function createViteLoader(root: string): Promise { +async function createViteLoader(root: string, fs: typeof fsType): Promise { const viteServer = await vite.createServer({ server: { middlewareMode: true, hmr: false }, optimizeDeps: { entries: [] }, @@ -27,6 +28,7 @@ async function createViteLoader(root: string): Promise { // avoid `vite.createServer` and use `loadConfigFromFile` instead. external: ['@astrojs/tailwind', '@astrojs/mdx', '@astrojs/react'], }, + plugins: [ loadFallbackPlugin({ fs, root: pathToFileURL(root) })] }); return { @@ -103,17 +105,22 @@ export async function loadConfigWithVite({ // Try loading with Node import() if (/\.[cm]?js$/.test(file)) { - const config = await import(pathToFileURL(file).toString()); - return { - value: config.default ?? {}, - filePath: file, - }; + try { + const config = await import(pathToFileURL(file).toString()); + return { + value: config.default ?? {}, + filePath: file, + }; + } catch { + // We do not need to keep the error here because with fallback the error will be rethrown + // when/if it fails in Proload. + } } // Try Loading with Vite let loader: ViteLoader | undefined; try { - loader = await createViteLoader(root); + loader = await createViteLoader(root, fs); const mod = await loader.viteServer.ssrLoadModule(file); return { value: mod.default ?? {}, diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts index e725451d97..0b075e21a0 100644 --- a/packages/astro/src/core/create-vite.ts +++ b/packages/astro/src/core/create-vite.ts @@ -97,7 +97,7 @@ export async function createVite( }, plugins: [ configAliasVitePlugin({ settings }), - astroLoadFallbackPlugin({ fs, settings }), + astroLoadFallbackPlugin({ fs, root: settings.config.root }), astroVitePlugin({ settings, logging }), astroScriptsPlugin({ settings }), // The server plugin is for dev only and having it run during the build causes diff --git a/packages/astro/src/vite-plugin-load-fallback/index.ts b/packages/astro/src/vite-plugin-load-fallback/index.ts index eaff71bfcb..6a37af2230 100644 --- a/packages/astro/src/vite-plugin-load-fallback/index.ts +++ b/packages/astro/src/vite-plugin-load-fallback/index.ts @@ -8,12 +8,12 @@ type NodeFileSystemModule = typeof nodeFs; export interface LoadFallbackPluginParams { fs?: NodeFileSystemModule; - settings: AstroSettings; + root: URL; } export default function loadFallbackPlugin({ fs, - settings, + root, }: LoadFallbackPluginParams): vite.Plugin[] | false { // Only add this plugin if a custom fs implementation is provided. if (!fs || fs === nodeFs) { @@ -29,7 +29,7 @@ export default function loadFallbackPlugin({ return await fs.promises.readFile(id, 'utf-8'); } catch (e2) { try { - const fullpath = new URL('.' + id, settings.config.root); + const fullpath = new URL('.' + id, root); return await fs.promises.readFile(fullpath, 'utf-8'); } catch (e3) { // Let fall through to the next @@ -43,15 +43,23 @@ export default function loadFallbackPlugin({ name: 'astro:load-fallback', enforce: 'post', async resolveId(id, parent) { - if (id.startsWith('.') && parent && fs.existsSync(parent)) { - return npath.posix.join(npath.posix.dirname(parent), id); - } else { - let resolved = await this.resolve(id, parent, { skipSelf: true }); - if (resolved) { - return resolved.id; - } - return slashify(id); + // See if this can be loaded from our fs + if (parent) { + const candidateId = npath.posix.join(npath.posix.dirname(parent), id); + try { + // Check to see if this file exists and is not a directory. + const stats = await fs.promises.stat(candidateId); + if(!stats.isDirectory()) { + return candidateId; + } + } catch {} + } + + let resolved = await this.resolve(id, parent, { skipSelf: true }); + if (resolved) { + return resolved.id; } + return slashify(id); }, async load(id) { const source = await tryLoadModule(id); diff --git a/packages/astro/test/units/config/format.test.js b/packages/astro/test/units/config/format.test.js new file mode 100644 index 0000000000..d3ace26723 --- /dev/null +++ b/packages/astro/test/units/config/format.test.js @@ -0,0 +1,41 @@ +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; +import { fileURLToPath } from 'url'; + +import { + runInContainer, +} from '../../../dist/core/dev/index.js'; +import { openConfig, createSettings } from '../../../dist/core/config/index.js'; +import { createFs } from '../test-utils.js'; +import { defaultLogging } from '../../test-utils.js'; + +const root = new URL('../../fixtures/tailwindcss-ts/', import.meta.url); + +describe('Astro config formats', () => { + it('An mjs config can import TypeScript modules', async () => { + const fs = createFs( + { + '/src/pages/index.astro': ``, + '/src/stuff.ts': `export default 'works';`, + '/astro.config.mjs': ` + import stuff from './src/stuff.ts'; + export default {} + `, + }, + root + ); + + const { astroConfig } = await openConfig({ + cwd: root, + flags: {}, + cmd: 'dev', + logging: defaultLogging, + fsMod: fs + }); + const settings = createSettings(astroConfig); + + await runInContainer({ fs, root, settings }, () => { + expect(true).to.equal(true, 'We were able to get into the container which means the config loaded.'); + }); + }); +});