diff options
author | 2021-03-25 16:59:38 -0600 | |
---|---|---|
committer | 2021-03-25 16:59:38 -0600 | |
commit | 04a443a8887257e86d824bb22686a527f84c0875 (patch) | |
tree | b64a7cd8fa56e4c549a1b60afa63e611779eda53 /src | |
parent | 3db595937719b89956c594e4a76ee68ae8de098a (diff) | |
download | astro-04a443a8887257e86d824bb22686a527f84c0875.tar.gz astro-04a443a8887257e86d824bb22686a527f84c0875.tar.zst astro-04a443a8887257e86d824bb22686a527f84c0875.zip |
Add React component SSR (#28)
* Add React component SSR
* Add React component SSR
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/codegen.ts | 29 | ||||
-rw-r--r-- | src/compiler/index.ts | 12 | ||||
-rw-r--r-- | src/runtime.ts | 17 |
3 files changed, 32 insertions, 26 deletions
diff --git a/src/compiler/codegen.ts b/src/compiler/codegen.ts index 58c7a6c9d..c0d963703 100644 --- a/src/compiler/codegen.ts +++ b/src/compiler/codegen.ts @@ -10,7 +10,7 @@ import { walk } from 'estree-walker'; import babelParser from '@babel/parser'; import _babelGenerator from '@babel/generator'; import traverse from '@babel/traverse'; -import { ImportDeclaration,ExportNamedDeclaration, VariableDeclarator, Identifier, VariableDeclaration } from '@babel/types'; +import { ImportDeclaration, ExportNamedDeclaration, VariableDeclarator, Identifier, VariableDeclaration } from '@babel/types'; import { type } from 'node:os'; const babelGenerator: typeof _babelGenerator = @@ -111,10 +111,7 @@ const defaultExtensions: Readonly<Record<string, ValidExtensionPlugins>> = { '.svelte': 'svelte', }; -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) { const [name, kind] = _name.split(':'); @@ -136,7 +133,9 @@ function getComponentWrapper(_name: string, { type, plugin, url }: ComponentInfo case 'preact': { if (kind === 'dynamic') { return { - wrapper: `__preact_dynamic(${name}, new URL(${JSON.stringify(url.replace(/\.[^.]+$/, '.js'))}, \`http://TEST\${import.meta.url}\`).pathname, '${dynamicImports.get('preact')!}')`, + wrapper: `__preact_dynamic(${name}, new URL(${JSON.stringify(url.replace(/\.[^.]+$/, '.js'))}, \`http://TEST\${import.meta.url}\`).pathname, '${dynamicImports.get( + 'preact' + )!}')`, wrapperImport: `import {__preact_dynamic} from '${internalImport('render/preact.js')}';`, }; } else { @@ -177,7 +176,9 @@ function getComponentWrapper(_name: string, { type, plugin, url }: ComponentInfo case 'vue': { if (kind === 'dynamic') { return { - wrapper: `__vue_dynamic(${name}, new URL(${JSON.stringify(url.replace(/\.[^.]+$/, '.vue.js'))}, \`http://TEST\${import.meta.url}\`).pathname, '${dynamicImports.get('vue')!}')`, + wrapper: `__vue_dynamic(${name}, new URL(${JSON.stringify(url.replace(/\.[^.]+$/, '.vue.js'))}, \`http://TEST\${import.meta.url}\`).pathname, '${dynamicImports.get( + 'vue' + )!}')`, wrapperImport: `import {__vue_dynamic} from '${internalImport('render/vue.js')}';`, }; } else { @@ -207,8 +208,8 @@ function compileExpressionSafe(raw: string): string { async function acquireDynamicComponentImports(plugins: Set<ValidExtensionPlugins>, resolve: (s: string) => Promise<string>): Promise<DynamicImportMap> { const importMap: DynamicImportMap = new Map(); - for(let plugin of plugins) { - switch(plugin) { + for (let plugin of plugins) { + switch (plugin) { case 'vue': { importMap.set('vue', await resolve('vue')); break; @@ -236,9 +237,9 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro const componentExports: ExportNamedDeclaration[] = []; let script = ''; - let propsStatement: string = ''; + let propsStatement = ''; const importExportStatements: Set<string> = new Set(); - const components: Record<string, { type: string; url: string, plugin: string | undefined }> = {}; + const components: Record<string, { type: string; url: string; plugin: string | undefined }> = {}; const componentPlugins = new Set<ValidExtensionPlugins>(); if (ast.module) { @@ -277,9 +278,9 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro components[componentName] = { type: componentType, plugin, - url: importUrl + url: importUrl, }; - if(plugin) { + if (plugin) { componentPlugins.add(plugin); } importExportStatements.add(ast.module.content.slice(componentImport.start!, componentImport.end!)); @@ -293,7 +294,7 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro for (const componentExport of componentProps) { propsStatement += `${(componentExport.id as Identifier).name}`; if (componentExport.init) { - propsStatement += `= ${babelGenerator(componentExport.init!).code }`; + propsStatement += `= ${babelGenerator(componentExport.init!).code}`; } propsStatement += `,`; } diff --git a/src/compiler/index.ts b/src/compiler/index.ts index fea6b8a29..945d9bfc5 100644 --- a/src/compiler/index.ts +++ b/src/compiler/index.ts @@ -105,12 +105,11 @@ async function transformFromSource( } } - export async function compileComponent( source: string, { compileOptions = defaultCompileOptions, filename, projectRoot }: { compileOptions: CompileOptions; filename: string; projectRoot: string } ): 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'); // sort <style> tags first sourceJsx.items.sort((a, b) => (a.name === 'style' && b.name !== 'style' ? -1 : 0)); @@ -124,9 +123,9 @@ ${sourceJsx.imports.join('\n')} // \`__render()\`: Render the contents of the Astro module. import { h, Fragment } from '${internalImport('h.js')}'; -async function __render(props, ...children) { +async function __render(props, ...children) { ${sourceJsx.script} - return h(Fragment, null, ${sourceJsx.items.map(({ jsx }) => jsx).join(',')}); + return h(Fragment, null, ${sourceJsx.items.map(({ jsx }) => jsx).join(',')}); } export default __render; `; @@ -134,9 +133,8 @@ export default __render; if (isPage) { modJsx += ` // \`__renderPage()\`: Render the contents of the Astro module as a page. This is a special flow, -// triggered by loading a component directly by URL. +// triggered by loading a component directly by URL. export async function __renderPage({request, children, props}) { - const currentChild = { setup: typeof setup === 'undefined' ? (passthrough) => passthrough : setup, layout: typeof __layout === 'undefined' ? undefined : __layout, @@ -155,7 +153,7 @@ export async function __renderPage({request, children, props}) { props: {content: currentChild.content}, children: [childBodyResult], }); - } + } return childBodyResult; };\n`; diff --git a/src/runtime.ts b/src/runtime.ts index 5dd391fdd..c8431fdb0 100644 --- a/src/runtime.ts +++ b/src/runtime.ts @@ -63,7 +63,7 @@ async function load(config: RuntimeConfig, rawPathname: string | undefined): Pro try { const mod = await snowpackRuntime.importModule(selectedPageUrl); - const html = (await mod.exports.__renderPage({ + let html = (await mod.exports.__renderPage({ request: { host: fullurl.hostname, path: fullurl.pathname, @@ -73,6 +73,15 @@ async function load(config: RuntimeConfig, rawPathname: string | undefined): Pro props: {}, })) as string; + // inject styles + // TODO: handle this in compiler + const styleTags = Array.isArray(mod.css) && mod.css.length ? mod.css.reduce((markup, url) => `${markup}\n<link rel="stylesheet" type="text/css" href="${url}" />`, '') : ``; + if (html.indexOf('</head>') !== -1) { + html = html.replace('</head>', `${styleTags}</head>`); + } else { + html = styleTags + html; + } + return { statusCode: 200, contents: html, @@ -99,7 +108,7 @@ async function load(config: RuntimeConfig, rawPathname: string | undefined): Pro interface RuntimeOptions { logging: LogOptions; - env: 'dev' | 'build' + env: 'dev' | 'build'; } export async function createRuntime(astroConfig: AstroConfig, { env, logging }: RuntimeOptions) { @@ -113,9 +122,7 @@ export async function createRuntime(astroConfig: AstroConfig, { env, logging }: extensions?: Record<string, string>; } = { extensions, - resolve: env === 'dev' ? - async (pkgName: string) => snowpack.getUrlForPackage(pkgName) : - async (pkgName: string) => `/_snowpack/pkg/${pkgName}.js` + resolve: env === 'dev' ? async (pkgName: string) => snowpack.getUrlForPackage(pkgName) : async (pkgName: string) => `/_snowpack/pkg/${pkgName}.js`, }; /*if (existsSync(new URL('./package-lock.json', projectRoot))) { const pkgLockStr = await readFile(new URL('./package-lock.json', projectRoot), 'utf-8'); |