mirror of
https://github.com/withastro/astro.git
synced 2025-02-17 22:44:24 -05:00
Resolve component URLs during compilation (#40)
Previously dynamic component URLs were being resolved client-side in a weird way that only worked during dev. This change makes them handle during compilation, so it works in both (and improves readability of the dynamic import output).
This commit is contained in:
parent
7334a550d8
commit
4a732837cd
6 changed files with 28 additions and 16 deletions
|
@ -3,7 +3,7 @@ const { readFile } = require('fs').promises;
|
||||||
// Snowpack plugins must be CommonJS :(
|
// Snowpack plugins must be CommonJS :(
|
||||||
const transformPromise = import('./lib/compiler/index.js');
|
const transformPromise = import('./lib/compiler/index.js');
|
||||||
|
|
||||||
module.exports = function (snowpackConfig, { resolve, extensions } = {}) {
|
module.exports = function (snowpackConfig, { resolve, extensions, astroConfig } = {}) {
|
||||||
return {
|
return {
|
||||||
name: 'snowpack-astro',
|
name: 'snowpack-astro',
|
||||||
knownEntrypoints: ['deepmerge'],
|
knownEntrypoints: ['deepmerge'],
|
||||||
|
@ -16,6 +16,7 @@ module.exports = function (snowpackConfig, { resolve, extensions } = {}) {
|
||||||
const projectRoot = snowpackConfig.root;
|
const projectRoot = snowpackConfig.root;
|
||||||
const contents = await readFile(filePath, 'utf-8');
|
const contents = await readFile(filePath, 'utf-8');
|
||||||
const compileOptions = {
|
const compileOptions = {
|
||||||
|
astroConfig,
|
||||||
resolve,
|
resolve,
|
||||||
extensions,
|
extensions,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import type { LogOptions } from '../logger';
|
import type { LogOptions } from '../logger';
|
||||||
import type { ValidExtensionPlugins } from './astro';
|
import type { AstroConfig, ValidExtensionPlugins } from './astro';
|
||||||
|
|
||||||
export interface CompileOptions {
|
export interface CompileOptions {
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
resolve: (p: string) => Promise<string>;
|
resolve: (p: string) => Promise<string>;
|
||||||
|
astroConfig: AstroConfig;
|
||||||
extensions?: Record<string, ValidExtensionPlugins>;
|
extensions?: Record<string, ValidExtensionPlugins>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { CompileOptions } from '../@types/compiler';
|
import type { CompileOptions } from '../@types/compiler';
|
||||||
import type { ValidExtensionPlugins } from '../@types/astro';
|
import type { AstroConfig, ValidExtensionPlugins } from '../@types/astro';
|
||||||
import type { Ast, TemplateNode } from '../parser/interfaces';
|
import type { Ast, TemplateNode } from '../parser/interfaces';
|
||||||
import type { JsxItem, TransformResult } from '../@types/astro';
|
import type { JsxItem, TransformResult } from '../@types/astro';
|
||||||
|
|
||||||
|
@ -111,14 +111,25 @@ const defaultExtensions: Readonly<Record<string, ValidExtensionPlugins>> = {
|
||||||
|
|
||||||
type DynamicImportMap = Map<'vue' | 'react' | 'react-dom' | 'preact', string>;
|
type DynamicImportMap = Map<'vue' | 'react' | 'react-dom' | 'preact', string>;
|
||||||
|
|
||||||
function getComponentWrapper(_name: string, { type, plugin, url }: ComponentInfo, dynamicImports: DynamicImportMap) {
|
interface GetComponentWrapperOptions {
|
||||||
|
filename: string;
|
||||||
|
astroConfig: AstroConfig;
|
||||||
|
dynamicImports: DynamicImportMap;
|
||||||
|
}
|
||||||
|
function getComponentWrapper(_name: string, { type, plugin, url }: ComponentInfo, opts: GetComponentWrapperOptions) {
|
||||||
|
const { astroConfig, dynamicImports, filename } = opts;
|
||||||
|
const { astroRoot } = astroConfig;
|
||||||
const [name, kind] = _name.split(':');
|
const [name, kind] = _name.split(':');
|
||||||
|
const currFileUrl = new URL(`file://${filename}`);
|
||||||
|
|
||||||
if (!plugin) {
|
if (!plugin) {
|
||||||
throw new Error(`No supported plugin found for extension ${type}`);
|
throw new Error(`No supported plugin found for extension ${type}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getComponentUrl = (ext = '.js') => `new URL(${JSON.stringify(url.replace(/\.[^.]+$/, ext))}, \`http://TEST\${import.meta.url\}\`).pathname.replace(/^\\/\\//, '/_astro/')`;
|
const getComponentUrl = (ext = '.js') => {
|
||||||
|
const outUrl = new URL(url, currFileUrl);
|
||||||
|
return '/_astro/' + path.posix.relative(astroRoot.pathname, outUrl.pathname).replace(/\.[^.]+$/, ext);
|
||||||
|
};
|
||||||
|
|
||||||
switch (plugin) {
|
switch (plugin) {
|
||||||
case 'astro': {
|
case 'astro': {
|
||||||
|
@ -242,8 +253,8 @@ async function acquireDynamicComponentImports(plugins: Set<ValidExtensionPlugins
|
||||||
return importMap;
|
return importMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Promise<TransformResult> {
|
export async function codegen(ast: Ast, { compileOptions, filename }: CodeGenOptions): Promise<TransformResult> {
|
||||||
const { extensions = defaultExtensions } = compileOptions;
|
const { extensions = defaultExtensions, astroConfig } = compileOptions;
|
||||||
await eslexer.init;
|
await eslexer.init;
|
||||||
|
|
||||||
const componentImports: ImportDeclaration[] = [];
|
const componentImports: ImportDeclaration[] = [];
|
||||||
|
@ -343,7 +354,7 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
|
||||||
if (!components[componentName]) {
|
if (!components[componentName]) {
|
||||||
throw new Error(`Unknown Component: ${componentName}`);
|
throw new Error(`Unknown Component: ${componentName}`);
|
||||||
}
|
}
|
||||||
const { wrapper, wrapperImport } = getComponentWrapper(name, components[componentName], dynamicImports);
|
const { wrapper, wrapperImport } = getComponentWrapper(name, components[componentName], {astroConfig, dynamicImports, filename});
|
||||||
if (wrapperImport) {
|
if (wrapperImport) {
|
||||||
importExportStatements.add(wrapperImport);
|
importExportStatements.add(wrapperImport);
|
||||||
}
|
}
|
||||||
|
@ -395,7 +406,7 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
|
||||||
if (!componentImportData) {
|
if (!componentImportData) {
|
||||||
throw new Error(`Unknown Component: ${componentName}`);
|
throw new Error(`Unknown Component: ${componentName}`);
|
||||||
}
|
}
|
||||||
const { wrapper, wrapperImport } = getComponentWrapper(name, components[componentName], dynamicImports);
|
const { wrapper, wrapperImport } = getComponentWrapper(name, components[componentName], {astroConfig, dynamicImports, filename});
|
||||||
if (wrapperImport) {
|
if (wrapperImport) {
|
||||||
importExportStatements.add(wrapperImport);
|
importExportStatements.add(wrapperImport);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import type { LogOptions } from '../logger.js';
|
import type { LogOptions } from '../logger.js';
|
||||||
|
import type { AstroConfig } from '../@types/astro';
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import micromark from 'micromark';
|
import micromark from 'micromark';
|
||||||
|
@ -14,15 +15,11 @@ import { optimize } from './optimize/index.js';
|
||||||
import { codegen } from './codegen.js';
|
import { codegen } from './codegen.js';
|
||||||
|
|
||||||
interface CompileOptions {
|
interface CompileOptions {
|
||||||
|
astroConfig: AstroConfig;
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
resolve: (p: string) => Promise<string>;
|
resolve: (p: string) => Promise<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultCompileOptions: CompileOptions = {
|
|
||||||
logging: defaultLogOptions,
|
|
||||||
resolve: (p: string) => Promise.resolve(p),
|
|
||||||
};
|
|
||||||
|
|
||||||
function internalImport(internalPath: string) {
|
function internalImport(internalPath: string) {
|
||||||
return `/_astro_internal/${internalPath}`;
|
return `/_astro_internal/${internalPath}`;
|
||||||
}
|
}
|
||||||
|
@ -107,7 +104,7 @@ async function transformFromSource(
|
||||||
|
|
||||||
export async function compileComponent(
|
export async function compileComponent(
|
||||||
source: string,
|
source: string,
|
||||||
{ compileOptions = defaultCompileOptions, filename, projectRoot }: { compileOptions: CompileOptions; filename: string; projectRoot: string }
|
{ compileOptions, filename, projectRoot }: { compileOptions: CompileOptions; filename: string; projectRoot: string }
|
||||||
): Promise<CompileResult> {
|
): Promise<CompileResult> {
|
||||||
const sourceJsx = await transformFromSource(source, { compileOptions, filename, projectRoot });
|
const sourceJsx = await transformFromSource(source, { compileOptions, filename, projectRoot });
|
||||||
const isPage = path.extname(filename) === '.md' || sourceJsx.items.some((item) => item.name === 'html');
|
const isPage = path.extname(filename) === '.md' || sourceJsx.items.some((item) => item.name === 'html');
|
||||||
|
|
|
@ -23,7 +23,7 @@ export function createRenderer(renderer: Renderer) {
|
||||||
return [...acc, `import("${context.frameworkUrls[lib as any]}")`];
|
return [...acc, `import("${context.frameworkUrls[lib as any]}")`];
|
||||||
}, [])
|
}, [])
|
||||||
.join(',');
|
.join(',');
|
||||||
return `const [{${context.componentExport}: Component}, ${values}] = await Promise.all([import(${context.componentUrl})${renderer.imports ? ', ' + libs : ''}]);`;
|
return `const [{${context.componentExport}: Component}, ${values}] = await Promise.all([import("${context.componentUrl}")${renderer.imports ? ', ' + libs : ''}]);`;
|
||||||
};
|
};
|
||||||
const serializeProps = (props: Record<string, any>) => JSON.stringify(props);
|
const serializeProps = (props: Record<string, any>) => JSON.stringify(props);
|
||||||
const createContext = () => {
|
const createContext = () => {
|
||||||
|
|
|
@ -126,7 +126,9 @@ export async function createRuntime(astroConfig: AstroConfig, { logging }: Runti
|
||||||
const astroPlugOptions: {
|
const astroPlugOptions: {
|
||||||
resolve?: (s: string) => Promise<string>;
|
resolve?: (s: string) => Promise<string>;
|
||||||
extensions?: Record<string, string>;
|
extensions?: Record<string, string>;
|
||||||
|
astroConfig: AstroConfig;
|
||||||
} = {
|
} = {
|
||||||
|
astroConfig,
|
||||||
extensions,
|
extensions,
|
||||||
resolve: async (pkgName: string) => snowpack.getUrlForPackage(pkgName),
|
resolve: async (pkgName: string) => snowpack.getUrlForPackage(pkgName),
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue