summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/snowpack/astro/components/Card.css67
-rw-r--r--examples/snowpack/astro/components/Card.jsx19
-rw-r--r--examples/snowpack/astro/pages/guides.astro9
-rw-r--r--examples/snowpack/public/css/components/_card-grid.scss64
-rw-r--r--snowpack-plugin.cjs2
-rw-r--r--src/compiler/codegen.ts29
-rw-r--r--src/compiler/index.ts12
-rw-r--r--src/runtime.ts17
8 files changed, 123 insertions, 96 deletions
diff --git a/examples/snowpack/astro/components/Card.css b/examples/snowpack/astro/components/Card.css
new file mode 100644
index 000000000..2fa7efe20
--- /dev/null
+++ b/examples/snowpack/astro/components/Card.css
@@ -0,0 +1,67 @@
+.card {
+ display: flex;
+ grid-column: span 1;
+ overflow: hidden;
+ font-family: Open Sans, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI,
+ Roboto, sans-serif;
+ color: #1a202c;
+ -webkit-font-smoothing: antialiased;
+ box-sizing: border-box;
+ border: 1px solid #e2e8f0;
+}
+
+.card:hover {
+ border-color: #2a85ca;
+ box-shadow: 0 2px 2px 0 rgba(46, 94, 130, 0.4);
+}
+
+.card:hover .card-image {
+ opacity: 0.9;
+}
+
+.card:nth-child(4n + 0) .card-image {
+ background: #f2709c;
+ background: linear-gradient(30deg, #ff9472, #f2709c);
+}
+
+.card:nth-child(4n + 1) .card-image {
+ background: #fbd3e9;
+ background: linear-gradient(30deg, #bb377d, #fbd3e9);
+}
+
+.card:nth-child(4n + 2) .card-image {
+ background: #b993d6;
+ background: linear-gradient(30deg, #8ca6db, #b993d6);
+}
+
+.card:nth-child(4n + 3) .card-image {
+ background: #00d2ff;
+ background: linear-gradient(30deg, #3a7bd5, #00d2ff);
+}
+
+.card-image {
+ width: 100%;
+ object-fit: cover;
+ opacity: 0.8;
+}
+
+.card-image__sm {
+ flex-grow: 1;
+ height: 120px;
+}
+
+.card-image__lg {
+ height: 200px;
+}
+
+.card-text {
+ padding: 1rem;
+}
+
+.card-title {
+ margin: 0 0 0.25rem 0;
+ font-weight: 600;
+ font-size: 20px;
+ font-family: 'Overpass';
+ line-height: 1.1;
+}
diff --git a/examples/snowpack/astro/components/Card.jsx b/examples/snowpack/astro/components/Card.jsx
index a7e2dc4eb..ee9460dcf 100644
--- a/examples/snowpack/astro/components/Card.jsx
+++ b/examples/snowpack/astro/components/Card.jsx
@@ -1,5 +1,6 @@
-import {h} from 'preact';
-import {format as formatDate, parseISO} from 'date-fns';
+import { h } from 'preact';
+import { format as formatDate, parseISO } from 'date-fns';
+import './Card.css';
export default function Card({ item }) {
return (
@@ -10,18 +11,24 @@ export default function Card({ item }) {
>
{item.img ? (
<img
- class="card-image card-image-small"
+ class="card-image card-image__sm"
src={item.img}
alt=""
style={{ background: item.imgBackground || undefined }}
/>
) : (
- <div class="card-image card-image-small"></div>
+ <div class="card-image card-image__sm"></div>
)}
<div class="card-text">
<h3 class="card-title">{item.title}</h3>
- {item.date && <time class="snow-toc-link">{ formatDate(parseISO(item.date), 'MMMM d, yyyy') }</time>}
- {item.description && <p style="margin: 0.5rem 0 0.25rem;">{ item.description }</p>}
+ {item.date && (
+ <time class="snow-toc-link">
+ {formatDate(parseISO(item.date), 'MMMM d, yyyy')}
+ </time>
+ )}
+ {item.description && (
+ <p style="margin: 0.5rem 0 0.25rem;">{item.description}</p>
+ )}
</div>
</a>
</article>
diff --git a/examples/snowpack/astro/pages/guides.astro b/examples/snowpack/astro/pages/guides.astro
index 3febcb2f7..f3d8d7179 100644
--- a/examples/snowpack/astro/pages/guides.astro
+++ b/examples/snowpack/astro/pages/guides.astro
@@ -76,8 +76,15 @@ let communityGuides;
return
<Card item={post} />;
})}
+ <Card item={{
+ url: 'https://www.snowpack.dev/posts/2021-01-13-snowpack-3-0',
+ img: 'https://www.snowpack.dev/img/social-snowpackv3.jpg',
+ date: '2021-01-12 00:00:00Z',
+ title: 'Snowpack v3.0',
+ description: 'Snowpack v3.0 is here!',
+ }} />
</div>
</MainLayout>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/examples/snowpack/public/css/components/_card-grid.scss b/examples/snowpack/public/css/components/_card-grid.scss
index 5bfb8eee4..5b0d25da8 100644
--- a/examples/snowpack/public/css/components/_card-grid.scss
+++ b/examples/snowpack/public/css/components/_card-grid.scss
@@ -8,9 +8,11 @@
.card-grid-3 {
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
+
.card-grid-4 {
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
+
.discord-banner {
grid-column: 1 / -1;
border: 1px solid #2e2077;
@@ -38,68 +40,6 @@
}
}
-.card {
- display: flex;
- grid-column: span 1;
- overflow: hidden;
- font-family: Open Sans, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI,
- Roboto, sans-serif;
- color: #1a202c;
- -webkit-font-smoothing: antialiased;
- box-sizing: border-box;
- border: 1px solid #e2e8f0;
-}
-.card:hover {
- border-color: #2a85ca;
- box-shadow: 0 2px 2px 0 rgba(46, 94, 130, 0.4);
-}
-.card:hover .card-image {
- opacity: 0.9;
-}
-
-.card-image {
- width: 100%;
- object-fit: cover;
- opacity: 0.8;
-}
-
-
-.card-image-small {
- flex-grow: 1;
- height: 120px;
-}
-
-.card-image-large {
- height: 200px;
-}
-.card-text {
- padding: 1rem;
-}
-.card-title {
- margin: 0 0 0.25rem 0;
- font-weight: 600;
- font-size: 20px;
- font-family: 'Overpass';
- line-height: 1.1;
-}
.content-title {
font-family: 'Overpass';
}
-
-.card:nth-child(4n + 0) .card-image {
- background: #f2709c;
- background: linear-gradient(30deg, #ff9472, #f2709c);
-}
-.card:nth-child(4n + 1) .card-image {
- background: #fbd3e9;
- background: linear-gradient(30deg, #bb377d, #fbd3e9);
-}
-.card:nth-child(4n + 2) .card-image {
- background: #b993d6;
- background: linear-gradient(30deg, #8ca6db, #b993d6);
-}
-
-.card:nth-child(4n + 3) .card-image {
- background: #00d2ff;
- background: linear-gradient(30deg, #3a7bd5, #00d2ff);
-}
diff --git a/snowpack-plugin.cjs b/snowpack-plugin.cjs
index 6b5e76a5b..f4f2edb81 100644
--- a/snowpack-plugin.cjs
+++ b/snowpack-plugin.cjs
@@ -17,7 +17,7 @@ module.exports = function (snowpackConfig, { resolve, extensions } = {}) {
const contents = await readFile(filePath, 'utf-8');
const compileOptions = {
resolve,
- extensions
+ extensions,
};
const result = await compileComponent(contents, { compileOptions, filename: filePath, projectRoot });
return result.contents;
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');