Skip to content

Commit

Permalink
Fix portfolio example
Browse files Browse the repository at this point in the history
  • Loading branch information
drwpow committed Oct 25, 2021
1 parent 7f95d70 commit 7314a7a
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 87 deletions.
26 changes: 8 additions & 18 deletions examples/portfolio/src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -190,28 +190,19 @@ const featuredProject = projects[0];
height="1131"
class="img"
src="https://images.unsplash.com/photo-1469854523086-cc02fe5d8800?w=1200&q=75"
srcSet="https://images.unsplash.com/photo-1469854523086-cc02fe5d8800?w=1200&q=75 800w,
https://images.unsplash.com/photo-1469854523086-cc02fe5d8800?w=1200&q=75 1200w,
https://images.unsplash.com/photo-1469854523086-cc02fe5d8800?w=1600&q=75 1600w,
https://images.unsplash.com/photo-1469854523086-cc02fe5d8800?w=2400&q=75 2400w,"
srcSet="https://images.unsplash.com/photo-1469854523086-cc02fe5d8800?w=1200&q=75 800w,https://images.unsplash.com/photo-1469854523086-cc02fe5d8800?w=1200&q=75 1200w,https://images.unsplash.com/photo-1469854523086-cc02fe5d8800?w=1600&q=75 1600w,https://images.unsplash.com/photo-1469854523086-cc02fe5d8800?w=2400&q=75 2400w"
sizes="(max-width: 800px) 800px, (max-width: 1200px) 1200px, (max-width: 1600px) 1600px, (max-width: 2400px) 2400px, 1200px"
/>
<div class="gradient" />
<div class="gradient2" />
>
<div class="gradient"></div>
<div class="gradient2"></div>
<div class="overlay">
<h1 class="title">
<small class="subtitle">The personal site of </small>Jeanine White
</h1>
<div>
<span class="role">
👩‍💻 Developer <span class="invert">👩‍💻 Developer</span>
</span>&nbsp;
<span class="role">
🎤 Speaker <span class="invert">🎤 Speaker</span>
</span>&nbsp;
<span class="role">
✏️ Writer <span class="invert">✏️ Writer</span>
</span>
<span class="role">👩‍💻 Developer <span class="invert">👩‍💻 Developer</span></span>&nbsp;
<span class="role">🎤 Speaker <span class="invert">🎤 Speaker</span></span>&nbsp;
<span class="role">✏️ Writer <span class="invert">✏️ Writer</span></span>
</div>
<p class="desc">Lover of dogs, roadtrips, and poetry.</p>
</div>
Expand All @@ -233,8 +224,7 @@ const featuredProject = projects[0];
<span>Hello!</span> I’m Jeanine, and this is my website. It was made using{' '}
<a href="https://github.com/snowpackjs/astro" target="_blank" rel="nofollow">
Astro
</a>
, a new way to build static sites. This is just an example template for you to modify.
</a>, a new way to build static sites. This is just an example template for you to modify.
</p>
<p>
<a href="/about">Read more</a>
Expand Down
5 changes: 3 additions & 2 deletions packages/astro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"test": "mocha --parallel --timeout 15000"
},
"dependencies": {
"@astrojs/compiler": "^0.2.16",
"@astrojs/compiler": "0.2.16-rc.1",
"@astrojs/language-server": "^0.7.16",
"@astrojs/markdown-remark": "^0.3.1",
"@astrojs/markdown-support": "0.3.1",
Expand All @@ -73,13 +73,14 @@
"estree-util-value-to-estree": "^1.2.0",
"fast-xml-parser": "^3.19.0",
"html-entities": "^2.3.2",
"htmlparser2": "^7.1.2",
"kleur": "^4.1.4",
"mime": "^2.5.2",
"morphdom": "^2.6.1",
"node-fetch": "^2.6.5",
"path-to-regexp": "^6.2.0",
"remark-slug": "^7.0.0",
"sass": "^1.43.2",
"sass": "^1.43.3",
"semver": "^7.3.5",
"send": "^0.17.1",
"shiki": "^0.9.10",
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/@types/astro-public.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { AstroConfig, AstroUserConfig } from './astro-core';
export { AstroConfig, AstroUserConfig } from './astro-core.js';
64 changes: 64 additions & 0 deletions packages/astro/src/core/ssr/css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import type vite from '../../../vendor/vite';

import path from 'path';
import htmlparser2 from 'htmlparser2';

// https://vitejs.dev/guide/features.html#css-pre-processors
export const STYLE_EXTENSIONS = new Set(['.css', '.scss', '.sass', '.styl', '.stylus', '.less']);
export const PREPROCESSOR_EXTENSIONS = new Set(['.scss', '.sass', '.styl', '.stylus', '.less']);

/** find unloaded styles */
export function getStylesForID(id: string, viteServer: vite.ViteDevServer): Set<string> {
const css = new Set<string>();
const { idToModuleMap } = viteServer.moduleGraph;
const moduleGraph = idToModuleMap.get(id);
if (!moduleGraph) return css;

// recursively crawl module graph to get all style files imported by parent id
function crawlCSS(entryModule: string, scanned = new Set<string>()) {
const moduleName = idToModuleMap.get(entryModule);
if (!moduleName) return;
for (const importedModule of moduleName.importedModules) {
if (!importedModule.id || scanned.has(importedModule.id)) return;
const ext = path.extname(importedModule.id.toLowerCase());

if (STYLE_EXTENSIONS.has(ext)) {
css.add(importedModule.id); // if style file, add to list
} else {
crawlCSS(importedModule.id, scanned); // otherwise, crawl file to see if it imports any CSS
}
scanned.add(importedModule.id);
}
}
crawlCSS(id);

return css;
}

/** add CSS <link> tags to HTML */
export function addLinkTagsToHTML(html: string, styles: Set<string>): string {
let output = html;

try {
// get position of </head>
let headEndPos = -1;
const parser = new htmlparser2.Parser({
onclosetag(tagname) {
if (tagname === 'head') {
headEndPos = parser.startIndex;
}
},
});
parser.write(html);
parser.end();

// update html
if (headEndPos !== -1) {
output = html.substring(0, headEndPos) + [...styles].map((href) => `<link rel="stylesheet" type="text/css" href="${href}">`).join('') + html.substring(headEndPos);
}
} catch (err) {
// on invalid HTML, do nothing
}

return output;
}
12 changes: 10 additions & 2 deletions packages/astro/src/core/ssr/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import fs from 'fs';
import path from 'path';
import { renderPage, renderSlot } from '../../runtime/server/index.js';
import { canonicalURL as getCanonicalURL, codeFrame } from '../util.js';
import { addLinkTagsToHTML, getStylesForID } from './css.js';
import { generatePaginateFunction } from './paginate.js';
import { getParams, validateGetStaticPathsModule, validateGetStaticPathsResult } from './routing.js';

Expand Down Expand Up @@ -148,18 +149,25 @@ export async function ssr({ astroConfig, filePath, logging, mode, origin, pathna
({ default: render } = await import(render));
}
const { code } = await render(content, { ...renderOpts, ...(opts ?? {}) });
return code
}
return code;
},
} as unknown as AstroGlobal;
},
_metadata: { renderers },
};

let html = await renderPage(result, Component, pageProps, null);

// run transformIndexHtml() in development to add HMR client to the page.
if (mode === 'development') {
html = await viteServer.transformIndexHtml(fileURLToPath(filePath), html, pathname);
}

// insert CSS imported from Astro and JS components
const styles = getStylesForID(fileURLToPath(filePath), viteServer);
const relativeStyles = new Set<string>([...styles].map((url) => url.replace(fileURLToPath(astroConfig.projectRoot), '/')));
html = addLinkTagsToHTML(html, relativeStyles);

return html;
} catch (e: any) {
viteServer.ssrFixStacktrace(e);
Expand Down
28 changes: 12 additions & 16 deletions packages/astro/src/runtime/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ function extractDirectives(inputProps: Record<string | number, any>): ExtractedP
}
} else if (key === 'class:list') {
// support "class" from an expression passed into a component (#782)
extracted.props[key.slice(0, -5)] = serializeListValue(value)
extracted.props[key.slice(0, -5)] = serializeListValue(value);
} else {
extracted.props[key] = value;
}
Expand Down Expand Up @@ -308,29 +308,25 @@ export function spreadAttributes(values: Record<any, any>) {
}

function serializeListValue(value: any) {
const hash: Record<string, any> = {}
const hash: Record<string, any> = {};

push(value)
push(value);

return Object.keys(hash).join(' ');

function push(item: any) {
// push individual iteratables
if (item && typeof item.forEach === 'function') item.forEach(push)

if (item && typeof item.forEach === 'function') item.forEach(push);
// otherwise, push object value keys by truthiness
else if (item === Object(item)) Object.keys(item).forEach(
name => {
if (item[name]) push(name)
}
)

else if (item === Object(item))
Object.keys(item).forEach((name) => {
if (item[name]) push(name);
});
// otherwise, push any other values as a string
else if (item = item != null && String(item).trim()) item.split(/\s+/).forEach(
(name: string) => {
hash[name] = true
}
)
else if ((item = item != null && String(item).trim()))
item.split(/\s+/).forEach((name: string) => {
hash[name] = true;
});
}
}

Expand Down
21 changes: 16 additions & 5 deletions packages/astro/src/vite-plugin-astro/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { TransformResult } from '@astrojs/compiler';
import type { SourceMapInput } from 'rollup';
import type vite from '../core/vite';
import type { AstroConfig } from '../@types/astro-core';

Expand All @@ -25,7 +26,7 @@ export default function astro({ config, devServer }: AstroPluginOptions): vite.P
viteTransform = getViteTransform(resolvedConfig);
},
// note: don’t claim .astro files with resolveId() — it prevents Vite from transpiling the final JS (import.meta.globEager, etc.)
async load(id) {
async load(id, ssr) {
if (!id.endsWith('.astro')) {
return null;
}
Expand All @@ -47,12 +48,20 @@ export default function astro({ config, devServer }: AstroPluginOptions): vite.P
internalURL: 'astro/internal',
preprocessStyle: async (value: string, attrs: Record<string, string>) => {
if (!attrs || !attrs.lang) return null;
const result = await transformWithVite(value, attrs, id, viteTransform);
const result = await transformWithVite({ value, attrs, id, transformHook: viteTransform, ssr });
if (!result) {
// TODO: compiler supports `null`, but types don't yet
return result as any;
}
return { code: result.code, map: result.map?.toString() };
let map: SourceMapInput | undefined;
if (result.map) {
if (typeof result.map === 'string') {
map = result.map;
} else if (result.map.mappings) {
map = result.map.toString();
}
}
return { code: result.code, map };
},
});
// Compile `.ts` to `.js`
Expand All @@ -63,12 +72,14 @@ export default function astro({ config, devServer }: AstroPluginOptions): vite.P
map,
};
} catch (err: any) {
// if esbuild threw the error, find original code source to display
// if esbuild threw the error, find original code source to display (if it’s mapped)
if (err.errors && tsResult?.map) {
const json = JSON.parse(tsResult.map);
const mappings = decode(json.mappings);
const focusMapping = mappings[err.errors[0].location.line + 1];
err.sourceLoc = { file: id, line: (focusMapping[0][2] || 0) + 1, column: (focusMapping[0][3] || 0) + 1 };
if (Array.isArray(focusMapping) && focusMapping.length) {
err.sourceLoc = { file: id, line: (focusMapping[0][2] || 0) + 1, column: (focusMapping[0][3] || 0) + 1 };
}
}
throw err;
}
Expand Down
24 changes: 16 additions & 8 deletions packages/astro/src/vite-plugin-astro/styles.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import type vite from '../core/vite';

export type TransformHook = (code: string, id: string, ssr?: boolean) => Promise<vite.TransformResult>;
import { PREPROCESSOR_EXTENSIONS } from '../core/ssr/css.js';

// https://vitejs.dev/guide/features.html#css-pre-processors
const SUPPORTED_PREPROCESSORS = new Set(['scss', 'sass', 'styl', 'stylus', 'less']);
export type TransformHook = (code: string, id: string, ssr?: boolean) => Promise<vite.TransformResult>;

/** Load vite:css’ transform() hook */
export function getViteTransform(viteConfig: vite.ResolvedConfig): TransformHook {
Expand All @@ -13,10 +12,19 @@ export function getViteTransform(viteConfig: vite.ResolvedConfig): TransformHook
return viteCSSPlugin.transform.bind(null as any) as any;
}

interface TransformWithViteOptions {
value: string;
attrs: Record<string, string>;
id: string;
transformHook: TransformHook;
ssr?: boolean;
}

/** Transform style using Vite hook */
export async function transformWithVite(value: string, attrs: Record<string, string>, id: string, transformHook: TransformHook): Promise<vite.TransformResult | null> {
const lang = (attrs.lang || '').toLowerCase(); // don’t be case-sensitive
if (!SUPPORTED_PREPROCESSORS.has(lang)) return null; // only preprocess the above
const result = await transformHook(value, id.replace(/\.astro$/, `.${lang}`));
return result || null;
export async function transformWithVite({ value, attrs, transformHook, id, ssr }: TransformWithViteOptions): Promise<vite.TransformResult | null> {
const lang = (`.${attrs.lang}` || '').toLowerCase(); // add leading "."; don’t be case-sensitive
if (!PREPROCESSOR_EXTENSIONS.has(lang)) {
return null; // only preprocess langs supported by Vite
}
return transformHook(value, id.replace(/\.astro$/, lang), ssr);
}
41 changes: 20 additions & 21 deletions packages/astro/test/astro-styles-ssr.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,24 @@ before(async () => {
});

describe('Styles SSR', () => {
// TODO: convert <style> to <link>
// it('Has <link> tags', async () => {
// const MUST_HAVE_LINK_TAGS = [
// '/src/components/ReactCSS.css',
// '/src/components/ReactModules.module.css',
// '/src/components/SvelteScoped.css',
// '/src/components/VueCSS.css',
// '/src/components/VueModules.css',
// '/src/components/VueScoped.css',
// ];

// const html = await fixture.readFile('/index.html');
// const $ = cheerio.load(html);

// for (const href of MUST_HAVE_LINK_TAGS) {
// const el = $(`link[href="${href}"]`);
// expect(el).to.have.lengthOf(1);
// }
// });
it('Has <link> tags', async () => {
const MUST_HAVE_LINK_TAGS = [
'/src/components/ReactCSS.css',
'/src/components/ReactModules.module.css',
'/src/components/SvelteScoped.svelte',
'/src/components/VueCSS.vue',
'/src/components/VueModules.vue',
'/src/components/VueScoped.vue',
];

const html = await fixture.readFile('/index.html');
const $ = cheerio.load(html);

for (const href of [...$('link[rel="stylesheet"]')].map((el) => el.attribs.href)) {
const hasTag = MUST_HAVE_LINK_TAGS.some((mustHaveHref) => href.includes(mustHaveHref));
expect(hasTag).to.equal(true);
}
});

it('Has correct CSS classes', async () => {
const html = await fixture.readFile('/index.html');
Expand Down Expand Up @@ -88,7 +87,7 @@ describe('Styles SSR', () => {
expect(wrapper).to.have.lengthOf(1);
});

// TODO: fix compiler bug
// TODO: add behavior in compiler
it.skip('Astro scoped styles', async () => {
const html = await fixture.readFile('/index.html');
const $ = cheerio.load(html);
Expand Down Expand Up @@ -126,7 +125,7 @@ describe('Styles SSR', () => {
expect($('#no-scope').attr('class')).to.equal(undefined);
});

// TODO: fix compiler bug
// TODO: add behavior in compiler
it.skip('Astro scoped styles can be passed to child components', async () => {
const html = await fixture.readFile('/index.html');
const $ = cheerio.load(html);
Expand Down
3 changes: 1 addition & 2 deletions packages/astro/test/preact-component.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ describe('Preact component', () => {
expect($('#class-component')).to.have.lengthOf(1);
});

// TODO: fix compiler bug (not interpreting <ArrowFunction /> as a component)
it.skip('Can load function component', async () => {
it('Can load function component', async () => {
const html = await fixture.readFile('/fn/index.html');
const $ = cheerio.load(html);

Expand Down
3 changes: 1 addition & 2 deletions packages/astro/test/react-component.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ describe('React Components', () => {
// test 2: no reactroot
expect($('#react-h2').attr('data-reactroot')).to.equal(undefined);

// TODO: fix compiler bug with arrow components
// test 3: Can use function components
// expect($('#arrow-fn-component')).to.have.lengthOf(1);
expect($('#arrow-fn-component')).to.have.lengthOf(1);

// test 4: Can use spread for components
expect($('#component-spread-props')).to.have.lengthOf(1);
Expand Down
Loading

0 comments on commit 7314a7a

Please sign in to comment.