Remove numbered comments (#1611)
* Chore: remove numbered comments * Clean up block comments
This commit is contained in:
parent
18222cf61b
commit
90b9c6e086
17 changed files with 148 additions and 96 deletions
|
@ -12,10 +12,10 @@ module.exports = {
|
||||||
'@typescript-eslint/no-unused-vars': 'off',
|
'@typescript-eslint/no-unused-vars': 'off',
|
||||||
'@typescript-eslint/no-use-before-define': 'off',
|
'@typescript-eslint/no-use-before-define': 'off',
|
||||||
'@typescript-eslint/no-var-requires': 'off',
|
'@typescript-eslint/no-var-requires': 'off',
|
||||||
|
'multiline-comment-style': ['warn', 'starred-block'],
|
||||||
'no-console': 'warn',
|
'no-console': 'warn',
|
||||||
'no-shadow': 'error',
|
'no-shadow': 'error',
|
||||||
'prefer-const': 'off',
|
'prefer-const': 'off',
|
||||||
'prefer-rest-params': 'off',
|
// 'require-jsdoc': 'error', // re-enable this to enforce JSDoc for all functions
|
||||||
'require-jsdoc': 'off',
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -63,7 +63,8 @@ export interface AstroUserConfig {
|
||||||
buildOptions?: {
|
buildOptions?: {
|
||||||
/** Your public domain, e.g.: https://my-site.dev/. Used to generate sitemaps and canonical URLs. */
|
/** Your public domain, e.g.: https://my-site.dev/. Used to generate sitemaps and canonical URLs. */
|
||||||
site?: string;
|
site?: string;
|
||||||
/** Generate an automatically-generated sitemap for your build.
|
/**
|
||||||
|
* Generate an automatically-generated sitemap for your build.
|
||||||
* Default: true
|
* Default: true
|
||||||
*/
|
*/
|
||||||
sitemap?: boolean;
|
sitemap?: boolean;
|
||||||
|
@ -95,14 +96,16 @@ export interface AstroUserConfig {
|
||||||
vite?: vite.InlineConfig;
|
vite?: vite.InlineConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(fks): We choose to keep our hand-generated AstroUserConfig interface so that
|
/*
|
||||||
// we can add JSDoc-style documentation and link to the definition file in our repo.
|
* NOTE(fks): We choose to keep our hand-generated AstroUserConfig interface so that
|
||||||
// However, Zod comes with the ability to auto-generate AstroConfig from the schema
|
* we can add JSDoc-style documentation and link to the definition file in our repo.
|
||||||
// above. If we ever get to the point where we no longer need the dedicated
|
* However, Zod comes with the ability to auto-generate AstroConfig from the schema
|
||||||
// @types/config.ts file, consider replacing it with the following lines:
|
* above. If we ever get to the point where we no longer need the dedicated
|
||||||
//
|
* @types/config.ts file, consider replacing it with the following lines:
|
||||||
// export interface AstroUserConfig extends z.input<typeof AstroConfigSchema> {
|
*
|
||||||
// }
|
* export interface AstroUserConfig extends z.input<typeof AstroConfigSchema> {
|
||||||
|
* }
|
||||||
|
*/
|
||||||
export type AstroConfig = z.output<typeof AstroConfigSchema>;
|
export type AstroConfig = z.output<typeof AstroConfigSchema>;
|
||||||
|
|
||||||
export type AsyncRendererComponentFn<U> = (Component: any, props: any, children: string | undefined, metadata?: AstroComponentMetadata) => Promise<U>;
|
export type AsyncRendererComponentFn<U> = (Component: any, props: any, children: string | undefined, metadata?: AstroComponentMetadata) => Promise<U>;
|
||||||
|
|
|
@ -55,7 +55,10 @@ class AstroBuilder {
|
||||||
async build() {
|
async build() {
|
||||||
const timer: Record<string, number> = {}; // keep track of performance timers
|
const timer: Record<string, number> = {}; // keep track of performance timers
|
||||||
|
|
||||||
// 1. initialize fresh Vite instance
|
/*
|
||||||
|
* Setup
|
||||||
|
* Create the Vite server with production build settings
|
||||||
|
*/
|
||||||
timer.viteStart = performance.now();
|
timer.viteStart = performance.now();
|
||||||
const { logging, origin } = this;
|
const { logging, origin } = this;
|
||||||
const viteConfig = await createVite(
|
const viteConfig = await createVite(
|
||||||
|
@ -73,12 +76,15 @@ class AstroBuilder {
|
||||||
this.viteServer = viteServer;
|
this.viteServer = viteServer;
|
||||||
debug(logging, 'build', timerMessage('Vite started', timer.viteStart));
|
debug(logging, 'build', timerMessage('Vite started', timer.viteStart));
|
||||||
|
|
||||||
// 2. get all routes
|
/*
|
||||||
|
* Render pages
|
||||||
|
* Convert .astro -> .html
|
||||||
|
*/
|
||||||
timer.renderStart = performance.now();
|
timer.renderStart = performance.now();
|
||||||
const assets: Record<string, string> = {}; // additional assets to be written
|
const assets: Record<string, string> = {}; // additional assets to be written
|
||||||
const allPages: Record<string, RouteData & { paths: string[] }> = {};
|
const allPages: Record<string, RouteData & { paths: string[] }> = {};
|
||||||
|
|
||||||
// 2a. determine all possible routes first before rendering
|
// pre-render: determine all possible routes from dynamic pages
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
this.manifest.routes.map(async (route) => {
|
this.manifest.routes.map(async (route) => {
|
||||||
// static route
|
// static route
|
||||||
|
@ -100,7 +106,7 @@ class AstroBuilder {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// 2b. after all paths have been determined, render all pages
|
// render: convert Astro to HTML
|
||||||
const input: InputHTMLOptions[] = [];
|
const input: InputHTMLOptions[] = [];
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
Object.entries(allPages).map(([component, route]) =>
|
Object.entries(allPages).map(([component, route]) =>
|
||||||
|
@ -126,7 +132,10 @@ class AstroBuilder {
|
||||||
);
|
);
|
||||||
debug(logging, 'build', timerMessage('All pages rendered', timer.renderStart));
|
debug(logging, 'build', timerMessage('All pages rendered', timer.renderStart));
|
||||||
|
|
||||||
// 3. build with Vite
|
/*
|
||||||
|
* Production Build
|
||||||
|
* Use Vite’s build process to generate files
|
||||||
|
*/
|
||||||
timer.buildStart = performance.now();
|
timer.buildStart = performance.now();
|
||||||
await vite.build({
|
await vite.build({
|
||||||
logLevel: 'error',
|
logLevel: 'error',
|
||||||
|
@ -151,7 +160,13 @@ class AstroBuilder {
|
||||||
});
|
});
|
||||||
debug(logging, 'build', timerMessage('Vite build finished', timer.buildStart));
|
debug(logging, 'build', timerMessage('Vite build finished', timer.buildStart));
|
||||||
|
|
||||||
// 4. write assets to disk
|
/*
|
||||||
|
* Post-build files
|
||||||
|
* Write other files to disk Vite may not know about.
|
||||||
|
* TODO: is there a way to handle these as part of the previous step?
|
||||||
|
*/
|
||||||
|
|
||||||
|
// RSS
|
||||||
timer.assetsStart = performance.now();
|
timer.assetsStart = performance.now();
|
||||||
Object.keys(assets).map((k) => {
|
Object.keys(assets).map((k) => {
|
||||||
if (!assets[k]) return;
|
if (!assets[k]) return;
|
||||||
|
@ -162,10 +177,9 @@ class AstroBuilder {
|
||||||
});
|
});
|
||||||
debug(logging, 'build', timerMessage('Additional assets copied', timer.assetsStart));
|
debug(logging, 'build', timerMessage('Additional assets copied', timer.assetsStart));
|
||||||
|
|
||||||
// 5. build sitemap
|
// Sitemap
|
||||||
timer.sitemapStart = performance.now();
|
timer.sitemapStart = performance.now();
|
||||||
if (this.config.buildOptions.sitemap && this.config.buildOptions.site) {
|
if (this.config.buildOptions.sitemap && this.config.buildOptions.site) {
|
||||||
const sitemapStart = performance.now();
|
|
||||||
const sitemap = generateSitemap(input.map(({ name }) => new URL(`/${name}`, this.config.buildOptions.site).href));
|
const sitemap = generateSitemap(input.map(({ name }) => new URL(`/${name}`, this.config.buildOptions.site).href));
|
||||||
const sitemapPath = new URL('./sitemap.xml', this.config.dist);
|
const sitemapPath = new URL('./sitemap.xml', this.config.dist);
|
||||||
await fs.promises.mkdir(new URL('./', sitemapPath), { recursive: true });
|
await fs.promises.mkdir(new URL('./', sitemapPath), { recursive: true });
|
||||||
|
@ -173,10 +187,11 @@ class AstroBuilder {
|
||||||
}
|
}
|
||||||
debug(logging, 'build', timerMessage('Sitemap built', timer.sitemapStart));
|
debug(logging, 'build', timerMessage('Sitemap built', timer.sitemapStart));
|
||||||
|
|
||||||
// 6. clean up
|
/*
|
||||||
|
* Clean up
|
||||||
|
* Close the Vite server instance, and print stats
|
||||||
|
*/
|
||||||
await viteServer.close();
|
await viteServer.close();
|
||||||
|
|
||||||
// 7. log output
|
|
||||||
if (logging.level && levels[logging.level] <= levels['info']) {
|
if (logging.level && levels[logging.level] <= levels['info']) {
|
||||||
await this.printStats({ cwd: this.config.dist, pageCount: input.length });
|
await this.printStats({ cwd: this.config.dist, pageCount: input.length });
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,8 +72,10 @@ export const AstroConfigSchema = z.object({
|
||||||
/** Turn raw config values into normalized values */
|
/** Turn raw config values into normalized values */
|
||||||
export async function validateConfig(userConfig: any, root: string): Promise<AstroConfig> {
|
export async function validateConfig(userConfig: any, root: string): Promise<AstroConfig> {
|
||||||
const fileProtocolRoot = pathToFileURL(root + path.sep);
|
const fileProtocolRoot = pathToFileURL(root + path.sep);
|
||||||
// We need to extend the global schema to add transforms that are relative to root.
|
/*
|
||||||
// This is type checked against the global schema to make sure we still match.
|
* We need to extend the global schema to add transforms that are relative to root.
|
||||||
|
* This is type checked against the global schema to make sure we still match.
|
||||||
|
*/
|
||||||
const AstroConfigRelativeSchema = AstroConfigSchema.extend({
|
const AstroConfigRelativeSchema = AstroConfigSchema.extend({
|
||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
|
|
|
@ -42,21 +42,21 @@ export async function createVite(
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
astroConfig.renderers.map(async (name) => {
|
astroConfig.renderers.map(async (name) => {
|
||||||
const { default: renderer } = await import(name);
|
const { default: renderer } = await import(name);
|
||||||
// 1. prepare client-side hydration code for browser
|
// prepare client-side hydration code for browser
|
||||||
if (renderer.client) {
|
if (renderer.client) {
|
||||||
optimizedDeps.add(name + renderer.client.substr(1));
|
optimizedDeps.add(name + renderer.client.substr(1));
|
||||||
}
|
}
|
||||||
// 2. knownEntrypoints and polyfills need to be added to the client
|
// knownEntrypoints and polyfills need to be added to the client
|
||||||
for (let dep of [...(renderer.knownEntrypoints || []), ...(renderer.polyfills || [])]) {
|
for (let dep of [...(renderer.knownEntrypoints || []), ...(renderer.polyfills || [])]) {
|
||||||
if (dep[0] === '.') dep = name + dep.substr(1); // if local polyfill, use full path
|
if (dep[0] === '.') dep = name + dep.substr(1); // if local polyfill, use full path
|
||||||
optimizedDeps.add(dep);
|
optimizedDeps.add(dep);
|
||||||
dedupe.add(dep); // we can try and dedupe renderers by default
|
dedupe.add(dep); // we can try and dedupe renderers by default
|
||||||
}
|
}
|
||||||
// 3. let renderer inject Vite plugins
|
// let renderer inject Vite plugins
|
||||||
if (renderer.vitePlugins) {
|
if (renderer.vitePlugins) {
|
||||||
plugins.push(...renderer.vitePlugins);
|
plugins.push(...renderer.vitePlugins);
|
||||||
}
|
}
|
||||||
// 4. mark external packages as external to Vite
|
// mark external packages as external to Vite
|
||||||
if (renderer.external) {
|
if (renderer.external) {
|
||||||
for (const dep of renderer.external) {
|
for (const dep of renderer.external) {
|
||||||
external.add(dep);
|
external.add(dep);
|
||||||
|
|
|
@ -70,18 +70,22 @@ export class AstroDevServer {
|
||||||
|
|
||||||
/** Start dev server */
|
/** Start dev server */
|
||||||
async start() {
|
async start() {
|
||||||
// 1. profile startup time
|
/*
|
||||||
const devStart = performance.now();
|
* Setup
|
||||||
|
* Create the Vite serer in dev mode
|
||||||
// 2. create Vite instance
|
*/
|
||||||
|
const devStart = performance.now(); // profile startup time
|
||||||
this.viteServer = await this.createViteServer();
|
this.viteServer = await this.createViteServer();
|
||||||
|
|
||||||
// 3. add middlewares
|
// middlewares
|
||||||
this.app.use((req, res, next) => this.handleRequest(req, res, next));
|
this.app.use((req, res, next) => this.handleRequest(req, res, next));
|
||||||
this.app.use(this.viteServer.middlewares);
|
this.app.use(this.viteServer.middlewares);
|
||||||
this.app.use((req, res, next) => this.renderError(req, res, next));
|
this.app.use((req, res, next) => this.renderError(req, res, next));
|
||||||
|
|
||||||
// 4. listen on port (and retry if taken)
|
/*
|
||||||
|
* Listen
|
||||||
|
* Start external connect server and listen on configured port
|
||||||
|
*/
|
||||||
await new Promise<void>((resolve, reject) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
const onError = (err: NodeJS.ErrnoException) => {
|
const onError = (err: NodeJS.ErrnoException) => {
|
||||||
if (err.code && err.code === 'EADDRINUSE') {
|
if (err.code && err.code === 'EADDRINUSE') {
|
||||||
|
@ -193,9 +197,11 @@ export class AstroDevServer {
|
||||||
this.manifest = createRouteManifest({ config: this.config });
|
this.manifest = createRouteManifest({ config: this.config });
|
||||||
});
|
});
|
||||||
viteServer.watcher.on('change', () => {
|
viteServer.watcher.on('change', () => {
|
||||||
// No need to rebuild routes on file content changes.
|
/*
|
||||||
// However, we DO want to clear the cache in case
|
* No need to rebuild routes on file content changes.
|
||||||
// the change caused a getStaticPaths() return to change.
|
* However, we DO want to clear the cache in case
|
||||||
|
* the change caused a getStaticPaths() return to change.
|
||||||
|
*/
|
||||||
this.routeCache = {};
|
this.routeCache = {};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,10 @@ function getLoggerLocale(): string {
|
||||||
const defaultLocale = 'en-US';
|
const defaultLocale = 'en-US';
|
||||||
if (process.env.LANG) {
|
if (process.env.LANG) {
|
||||||
const extractedLocale = process.env.LANG.split('.')[0].replace(/_/g, '-');
|
const extractedLocale = process.env.LANG.split('.')[0].replace(/_/g, '-');
|
||||||
// Check if language code is atleast two characters long (ie. en, es).
|
/*
|
||||||
// NOTE: if "c" locale is encountered, the default locale will be returned.
|
* Check if language code is at least two characters long (ie. en, es).
|
||||||
|
* NOTE: if "c" locale is encountered, the default locale will be returned.
|
||||||
|
*/
|
||||||
if (extractedLocale.length < 2) return defaultLocale;
|
if (extractedLocale.length < 2) return defaultLocale;
|
||||||
else return extractedLocale;
|
else return extractedLocale;
|
||||||
} else return defaultLocale;
|
} else return defaultLocale;
|
||||||
|
|
|
@ -38,9 +38,11 @@ const cache = new Map<string, Promise<Renderer>>();
|
||||||
// TODO: improve validation and error handling here.
|
// TODO: improve validation and error handling here.
|
||||||
async function resolveRenderer(viteServer: ViteDevServer, renderer: string) {
|
async function resolveRenderer(viteServer: ViteDevServer, renderer: string) {
|
||||||
const resolvedRenderer: any = {};
|
const resolvedRenderer: any = {};
|
||||||
// We can dynamically import the renderer by itself because it shouldn't have
|
/*
|
||||||
// any non-standard imports, the index is just meta info.
|
* We can dynamically import the renderer by itself because it shouldn't have
|
||||||
// The other entrypoints need to be loaded through Vite.
|
* any non-standard imports, the index is just meta info.
|
||||||
|
* The other entrypoints need to be loaded through Vite.
|
||||||
|
*/
|
||||||
const {
|
const {
|
||||||
default: { name, client, polyfills, hydrationPolyfills, server },
|
default: { name, client, polyfills, hydrationPolyfills, server },
|
||||||
} = await import(renderer);
|
} = await import(renderer);
|
||||||
|
@ -73,14 +75,20 @@ async function resolveRenderers(viteServer: ViteDevServer, ids: string[]): Promi
|
||||||
/** use Vite to SSR */
|
/** use Vite to SSR */
|
||||||
export async function ssr({ astroConfig, filePath, logging, mode, origin, pathname, route, routeCache, viteServer }: SSROptions): Promise<string> {
|
export async function ssr({ astroConfig, filePath, logging, mode, origin, pathname, route, routeCache, viteServer }: SSROptions): Promise<string> {
|
||||||
try {
|
try {
|
||||||
// 1. resolve renderers
|
/*
|
||||||
|
* Renderers
|
||||||
|
* Load all renderers to be used for SSR
|
||||||
|
*/
|
||||||
// Important this happens before load module in case a renderer provides polyfills.
|
// Important this happens before load module in case a renderer provides polyfills.
|
||||||
const renderers = await resolveRenderers(viteServer, astroConfig.renderers);
|
const renderers = await resolveRenderers(viteServer, astroConfig.renderers);
|
||||||
|
|
||||||
// 2. load module
|
/*
|
||||||
|
* Pre-render
|
||||||
|
* Load module through Vite and do pre-render work like dynamic routing
|
||||||
|
*/
|
||||||
const mod = (await viteServer.ssrLoadModule(fileURLToPath(filePath))) as ComponentInstance;
|
const mod = (await viteServer.ssrLoadModule(fileURLToPath(filePath))) as ComponentInstance;
|
||||||
|
|
||||||
// 3. handle dynamic routes
|
// handle dynamic routes
|
||||||
let params: Params = {};
|
let params: Params = {};
|
||||||
let pageProps: Props = {};
|
let pageProps: Props = {};
|
||||||
if (route && !route.pathname) {
|
if (route && !route.pathname) {
|
||||||
|
@ -110,7 +118,10 @@ export async function ssr({ astroConfig, filePath, logging, mode, origin, pathna
|
||||||
pageProps = { ...matchedStaticPath.props } || {};
|
pageProps = { ...matchedStaticPath.props } || {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. render page
|
/*
|
||||||
|
* Render
|
||||||
|
* Convert .astro to .html
|
||||||
|
*/
|
||||||
const Component = await mod.default;
|
const Component = await mod.default;
|
||||||
if (!Component) throw new Error(`Expected an exported Astro component but received typeof ${typeof Component}`);
|
if (!Component) throw new Error(`Expected an exported Astro component but received typeof ${typeof Component}`);
|
||||||
|
|
||||||
|
@ -144,12 +155,14 @@ export async function ssr({ astroConfig, filePath, logging, mode, origin, pathna
|
||||||
|
|
||||||
let html = await renderPage(result, Component, pageProps, null);
|
let html = await renderPage(result, Component, pageProps, null);
|
||||||
|
|
||||||
// 5. modify response
|
/*
|
||||||
|
* Dev Server
|
||||||
|
* Apply Vite HMR, Astro HMR, and other dev-only transformations needed from Vite plugins.
|
||||||
|
*/
|
||||||
if (mode === 'development') {
|
if (mode === 'development') {
|
||||||
html = await viteServer.transformIndexHtml(fileURLToPath(filePath), html, pathname);
|
html = await viteServer.transformIndexHtml(fileURLToPath(filePath), html, pathname);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. finish
|
|
||||||
return html;
|
return html;
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
viteServer.ssrFixStacktrace(e);
|
viteServer.ssrFixStacktrace(e);
|
||||||
|
|
|
@ -1,15 +1,5 @@
|
||||||
import { GetStaticPathsResult, PaginatedCollectionProp, PaginateFunction, Params, Props, RouteData } from '../../@types/astro-core';
|
import { GetStaticPathsResult, PaginatedCollectionProp, PaginateFunction, Params, Props, RouteData } from '../../@types/astro-core';
|
||||||
|
|
||||||
// return filters.map((filter) => {
|
|
||||||
// const filteredRecipes = allRecipes.filter((recipe) =>
|
|
||||||
// filterKeys.some((key) => recipe[key] === filter)
|
|
||||||
// );
|
|
||||||
// return paginate(filteredRecipes, {
|
|
||||||
// params: { slug: slugify(filter) },
|
|
||||||
// props: { filter },
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
export function generatePaginateFunction(routeMatch: RouteData): PaginateFunction {
|
export function generatePaginateFunction(routeMatch: RouteData): PaginateFunction {
|
||||||
return function paginateUtility(data: any[], args: { pageSize?: number; params?: Params; props?: Props } = {}) {
|
return function paginateUtility(data: any[], args: { pageSize?: number; params?: Params; props?: Props } = {}) {
|
||||||
let { pageSize: _pageSize, params: _params, props: _props } = args;
|
let { pageSize: _pageSize, params: _params, props: _props } = args;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/** Construct sitemap.xml given a set of URLs */
|
/** Construct sitemap.xml given a set of URLs */
|
||||||
export function generateSitemap(pages: string[]): string {
|
export function generateSitemap(pages: string[]): string {
|
||||||
// TODO: find way to respect <link rel="canonical"> URLs here
|
// TODO: find way to respect <link rel="canonical"> URLs here
|
||||||
|
|
||||||
// TODO: find way to exclude pages from sitemap
|
// TODO: find way to exclude pages from sitemap
|
||||||
|
|
||||||
const urls = [...pages]; // copy just in case original copy is needed
|
const urls = [...pages]; // copy just in case original copy is needed
|
||||||
|
|
|
@ -52,20 +52,20 @@ export function codeFrame(src: string, loc: ErrorPayload['err']['loc']): string
|
||||||
|
|
||||||
const lines = src.replace(/\r\n/g, '\n').split('\n');
|
const lines = src.replace(/\r\n/g, '\n').split('\n');
|
||||||
|
|
||||||
// 1. grab 2 lines before, and 3 lines after focused line
|
// grab 2 lines before, and 3 lines after focused line
|
||||||
const visibleLines = [];
|
const visibleLines = [];
|
||||||
for (let n = -2; n <= 2; n++) {
|
for (let n = -2; n <= 2; n++) {
|
||||||
if (lines[loc.line + n]) visibleLines.push(loc.line + n);
|
if (lines[loc.line + n]) visibleLines.push(loc.line + n);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. figure out gutter width
|
// figure out gutter width
|
||||||
let gutterWidth = 0;
|
let gutterWidth = 0;
|
||||||
for (const lineNo of visibleLines) {
|
for (const lineNo of visibleLines) {
|
||||||
let w = `> ${lineNo}`;
|
let w = `> ${lineNo}`;
|
||||||
if (w.length > gutterWidth) gutterWidth = w.length;
|
if (w.length > gutterWidth) gutterWidth = w.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. print lines
|
// print lines
|
||||||
let output = '';
|
let output = '';
|
||||||
for (const lineNo of visibleLines) {
|
for (const lineNo of visibleLines) {
|
||||||
const isFocusedLine = lineNo === loc.line - 1;
|
const isFocusedLine = lineNo === loc.line - 1;
|
||||||
|
|
|
@ -10,14 +10,18 @@ export { createMetadata } from './metadata.js';
|
||||||
|
|
||||||
const { generate, GENERATOR } = astring;
|
const { generate, GENERATOR } = astring;
|
||||||
|
|
||||||
// A more robust version alternative to `JSON.stringify` that can handle most values
|
/*
|
||||||
// see https://github.com/remcohaszing/estree-util-value-to-estree#readme
|
* A more robust version alternative to `JSON.stringify` that can handle most values
|
||||||
|
* See https://github.com/remcohaszing/estree-util-value-to-estree#readme
|
||||||
|
*/
|
||||||
const customGenerator: astring.Generator = {
|
const customGenerator: astring.Generator = {
|
||||||
...GENERATOR,
|
...GENERATOR,
|
||||||
Literal(node, state) {
|
Literal(node, state) {
|
||||||
if (node.raw != null) {
|
if (node.raw != null) {
|
||||||
// escape closing script tags in strings so browsers wouldn't interpret them as
|
/*
|
||||||
// closing the actual end tag in HTML
|
* escape closing script tags in strings so browsers wouldn't interpret them as
|
||||||
|
* closing the actual end tag in HTML
|
||||||
|
*/
|
||||||
state.write(node.raw.replace('</script>', '<\\/script>'));
|
state.write(node.raw.replace('</script>', '<\\/script>'));
|
||||||
} else {
|
} else {
|
||||||
GENERATOR.Literal(node, state);
|
GENERATOR.Literal(node, state);
|
||||||
|
@ -35,9 +39,11 @@ async function _render(child: any): Promise<any> {
|
||||||
if (Array.isArray(child)) {
|
if (Array.isArray(child)) {
|
||||||
return (await Promise.all(child.map((value) => _render(value)))).join('\n');
|
return (await Promise.all(child.map((value) => _render(value)))).join('\n');
|
||||||
} else if (typeof child === 'function') {
|
} else if (typeof child === 'function') {
|
||||||
// Special: If a child is a function, call it automatically.
|
/*
|
||||||
// This lets you do {() => ...} without the extra boilerplate
|
* Special: If a child is a function, call it automatically.
|
||||||
// of wrapping it in a function and calling it.
|
* This lets you do {() => ...} without the extra boilerplate
|
||||||
|
* of wrapping it in a function and calling it.
|
||||||
|
*/
|
||||||
return _render(child());
|
return _render(child());
|
||||||
} else if (typeof child === 'string') {
|
} else if (typeof child === 'string') {
|
||||||
return child;
|
return child;
|
||||||
|
@ -261,7 +267,7 @@ function createFetchContentFn(url: URL) {
|
||||||
...mod.frontmatter,
|
...mod.frontmatter,
|
||||||
content: mod.metadata,
|
content: mod.metadata,
|
||||||
file: new URL(spec, url),
|
file: new URL(spec, url),
|
||||||
url: urlSpec.includes('/pages/') && urlSpec.replace(/^.*\/pages\//, '/').replace(/\.md$/, '')
|
url: urlSpec.includes('/pages/') && urlSpec.replace(/^.*\/pages\//, '/').replace(/\.md$/, ''),
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
|
|
|
@ -11,7 +11,7 @@ interface AstroPluginOptions {
|
||||||
devServer?: AstroDevServer;
|
devServer?: AstroDevServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// esbuild transforms the component-scoped Astro into Astro2, so need to check both.
|
// esbuild transforms the component-scoped Astro into Astro2, so need to check both.
|
||||||
const validAstroGlobalNames = new Set(['Astro', 'Astro2']);
|
const validAstroGlobalNames = new Set(['Astro', 'Astro2']);
|
||||||
|
|
||||||
export default function astro({ config, devServer }: AstroPluginOptions): Plugin {
|
export default function astro({ config, devServer }: AstroPluginOptions): Plugin {
|
||||||
|
@ -23,8 +23,10 @@ export default function astro({ config, devServer }: AstroPluginOptions): Plugin
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimization: only run on a probably match
|
/*
|
||||||
// Open this up if need for post-pass extends past fetchContent
|
* Optimization: only run on a probably match
|
||||||
|
* Open this up if need for post-pass extends past fetchContent
|
||||||
|
*/
|
||||||
if (!code.includes('fetchContent')) {
|
if (!code.includes('fetchContent')) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,15 +28,14 @@ export default function astro({ config, devServer }: AstroPluginOptions): Plugin
|
||||||
let tsResult: TransformResult | undefined;
|
let tsResult: TransformResult | undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. Transform from `.astro` to valid `.ts`
|
// `.astro` -> `.ts`
|
||||||
// use `sourcemap: "inline"` so that the sourcemap is included in the "code" result that we pass to esbuild.
|
|
||||||
tsResult = await transform(source, {
|
tsResult = await transform(source, {
|
||||||
site: config.buildOptions.site,
|
site: config.buildOptions.site,
|
||||||
sourcefile: id,
|
sourcefile: id,
|
||||||
sourcemap: 'both',
|
sourcemap: 'both',
|
||||||
internalURL: 'astro/internal',
|
internalURL: 'astro/internal',
|
||||||
});
|
});
|
||||||
// 2. Compile `.ts` to `.js`
|
// `.ts` -> `.js`
|
||||||
const { code, map } = await esbuild.transform(tsResult.code, { loader: 'ts', sourcemap: 'external', sourcefile: id });
|
const { code, map } = await esbuild.transform(tsResult.code, { loader: 'ts', sourcemap: 'external', sourcefile: id });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -4,19 +4,21 @@ import MagicString from 'magic-string';
|
||||||
// https://github.com/vitejs/vite/discussions/5109#discussioncomment-1450726
|
// https://github.com/vitejs/vite/discussions/5109#discussioncomment-1450726
|
||||||
function isSSR(options: undefined | boolean | { ssr: boolean }): boolean {
|
function isSSR(options: undefined | boolean | { ssr: boolean }): boolean {
|
||||||
if (options === undefined) {
|
if (options === undefined) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
if (typeof options === 'boolean') {
|
if (typeof options === 'boolean') {
|
||||||
return options
|
return options;
|
||||||
}
|
}
|
||||||
if (typeof options == 'object') {
|
if (typeof options == 'object') {
|
||||||
return !!options.ssr
|
return !!options.ssr;
|
||||||
}
|
}
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This matches any JS-like file (that we know of)
|
/*
|
||||||
// See https://regex101.com/r/Cgofir/1
|
* This matches any JS-like file (that we know of)
|
||||||
|
* See https://regex101.com/r/Cgofir/1
|
||||||
|
*/
|
||||||
const SUPPORTED_FILES = /\.(astro|svelte|vue|[cm]?js|jsx|[cm]?ts|tsx)$/;
|
const SUPPORTED_FILES = /\.(astro|svelte|vue|[cm]?js|jsx|[cm]?ts|tsx)$/;
|
||||||
const DEFINE_FETCH = `import fetch from 'node-fetch';\n`;
|
const DEFINE_FETCH = `import fetch from 'node-fetch';\n`;
|
||||||
|
|
||||||
|
@ -26,22 +28,22 @@ export default function pluginFetch(): Plugin {
|
||||||
enforce: 'post',
|
enforce: 'post',
|
||||||
async transform(code, id, opts) {
|
async transform(code, id, opts) {
|
||||||
const ssr = isSSR(opts);
|
const ssr = isSSR(opts);
|
||||||
|
|
||||||
// If this isn't an SSR pass, `fetch` will already be available!
|
// If this isn't an SSR pass, `fetch` will already be available!
|
||||||
if (!ssr) {
|
if (!ssr) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only transform JS-like files
|
// Only transform JS-like files
|
||||||
if (!id.match(SUPPORTED_FILES)) {
|
if (!id.match(SUPPORTED_FILES)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimization: only run on probable matches
|
// Optimization: only run on probable matches
|
||||||
if (!code.includes('fetch')) {
|
if (!code.includes('fetch')) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const s = new MagicString(code);
|
const s = new MagicString(code);
|
||||||
s.prepend(DEFINE_FETCH);
|
s.prepend(DEFINE_FETCH);
|
||||||
|
|
||||||
|
@ -49,10 +51,10 @@ export default function pluginFetch(): Plugin {
|
||||||
|
|
||||||
const map = s.generateMap({
|
const map = s.generateMap({
|
||||||
source: id,
|
source: id,
|
||||||
includeContent: true
|
includeContent: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
return { code: result, map }
|
return { code: result, map };
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,10 @@ const IMPORT_STATEMENTS: Record<string, string> = {
|
||||||
preact: "import { h } from 'preact'",
|
preact: "import { h } from 'preact'",
|
||||||
'solid-js': "import 'solid-js/web'",
|
'solid-js': "import 'solid-js/web'",
|
||||||
};
|
};
|
||||||
// The `tsx` loader in esbuild will remove unused imports, so we need to
|
/*
|
||||||
// be careful about esbuild not treating h, React, Fragment, etc. as unused.
|
* The `tsx` loader in esbuild will remove unused imports, so we need to
|
||||||
|
* be careful about esbuild not treating h, React, Fragment, etc. as unused.
|
||||||
|
*/
|
||||||
const PREVENT_UNUSED_IMPORTS = ';;(React,Fragment,h);';
|
const PREVENT_UNUSED_IMPORTS = ';;(React,Fragment,h);';
|
||||||
|
|
||||||
interface AstroPluginJSXOptions {
|
interface AstroPluginJSXOptions {
|
||||||
|
@ -53,14 +55,23 @@ export default function jsx({ config, logging }: AstroPluginJSXOptions): Plugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// attempt 0: if we only have one renderer, we can skip a bunch of work!
|
/*
|
||||||
|
* Single JSX renderer
|
||||||
|
* If we only have one renderer, we can skip a bunch of work!
|
||||||
|
*/
|
||||||
if (JSX_RENDERERS.size === 1) {
|
if (JSX_RENDERERS.size === 1) {
|
||||||
return transformJSX({ code, id, renderer: [...JSX_RENDERERS.values()][0], ssr: ssr || false });
|
return transformJSX({ code, id, renderer: [...JSX_RENDERERS.values()][0], ssr: ssr || false });
|
||||||
}
|
}
|
||||||
|
|
||||||
// attempt 1: try and guess framework from imports (file can’t import React and Preact)
|
/*
|
||||||
|
* Multiple JSX renderers
|
||||||
|
* Determine for each .jsx or .tsx file what it wants to use to Render
|
||||||
|
*/
|
||||||
|
|
||||||
// we need valid JS here, so we can use `h` and `Fragment` as placeholders
|
// we need valid JS here, so we can use `h` and `Fragment` as placeholders
|
||||||
|
|
||||||
|
// try and guess renderer from imports (file can’t import React and Preact)
|
||||||
|
|
||||||
// NOTE(fks, matthewp): Make sure that you're transforming the original contents here.
|
// NOTE(fks, matthewp): Make sure that you're transforming the original contents here.
|
||||||
const { code: codeToScan } = await esbuild.transform(code + PREVENT_UNUSED_IMPORTS, {
|
const { code: codeToScan } = await esbuild.transform(code + PREVENT_UNUSED_IMPORTS, {
|
||||||
loader: getLoader(path.extname(id)),
|
loader: getLoader(path.extname(id)),
|
||||||
|
@ -85,7 +96,7 @@ export default function jsx({ config, logging }: AstroPluginJSXOptions): Plugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// attempt 2: look for @jsxImportSource comment
|
// if no imports were found, look for @jsxImportSource comment
|
||||||
if (!importSource) {
|
if (!importSource) {
|
||||||
const multiline = code.match(/\/\*\*[\S\s]*\*\//gm) || [];
|
const multiline = code.match(/\/\*\*[\S\s]*\*\//gm) || [];
|
||||||
for (const comment of multiline) {
|
for (const comment of multiline) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ export default function markdown({ config }: AstroPluginOptions): Plugin {
|
||||||
if (id.endsWith('.md')) {
|
if (id.endsWith('.md')) {
|
||||||
let source = await fs.promises.readFile(id, 'utf8');
|
let source = await fs.promises.readFile(id, 'utf8');
|
||||||
|
|
||||||
// 2. Transform from `.md` to valid `.astro`
|
// `.md` -> `.astro`
|
||||||
let render = config.markdownOptions.render;
|
let render = config.markdownOptions.render;
|
||||||
let renderOpts = {};
|
let renderOpts = {};
|
||||||
if (Array.isArray(render)) {
|
if (Array.isArray(render)) {
|
||||||
|
@ -46,14 +46,14 @@ ${setup}
|
||||||
astroResult = `${prelude}\n${astroResult}`;
|
astroResult = `${prelude}\n${astroResult}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Transform from `.astro` to valid `.ts`
|
// `.astro` -> `.ts`
|
||||||
let { code: tsResult } = await transform(astroResult, { sourcefile: id, sourcemap: 'inline', internalURL: 'astro/internal' });
|
let { code: tsResult } = await transform(astroResult, { sourcefile: id, sourcemap: 'inline', internalURL: 'astro/internal' });
|
||||||
|
|
||||||
tsResult = `\nexport const metadata = ${JSON.stringify(metadata)};
|
tsResult = `\nexport const metadata = ${JSON.stringify(metadata)};
|
||||||
export const frontmatter = ${JSON.stringify(content)};
|
export const frontmatter = ${JSON.stringify(content)};
|
||||||
${tsResult}`;
|
${tsResult}`;
|
||||||
|
|
||||||
// 3. Compile `.ts` to `.js`
|
// `.ts` -> `.js`
|
||||||
const { code, map } = await esbuild.transform(tsResult, { loader: 'ts', sourcemap: 'inline', sourcefile: id });
|
const { code, map } = await esbuild.transform(tsResult, { loader: 'ts', sourcemap: 'inline', sourcefile: id });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
Loading…
Add table
Reference in a new issue