parent
fad2662486
commit
addd67d244
17 changed files with 76 additions and 62 deletions
5
.changeset/sour-students-remain.md
Normal file
5
.changeset/sour-students-remain.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Rename `astroConfig` to `pages` in config. Docs updated.
|
|
@ -6,8 +6,8 @@ To configure Astro, add an `astro.config.mjs` file in the root of your project.
|
|||
export default {
|
||||
/** Where to resolve all URLs relative to. Useful if you have a monorepo project. */
|
||||
projectRoot: '.',
|
||||
/** Path to Astro components, pages, and data */
|
||||
astroRoot: './src',
|
||||
/** Path to your site’s pages (routes) */
|
||||
pages: './src/pages',
|
||||
/** When running `astro build`, path to final static output */
|
||||
dist: './dist',
|
||||
/** A folder of static files Astro will copy to the root. Useful for favicons, images, and other files that don’t need processing. */
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
export default {
|
||||
projectRoot: '.',
|
||||
pages: './src/pages',
|
||||
public: './public',
|
||||
dist: './dist',
|
||||
buildOptions: {
|
||||
sitemap: true,
|
||||
site: 'https://mysite.dev/', // change
|
||||
},
|
||||
astroRoot: './src',
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export default {
|
||||
projectRoot: '.',
|
||||
astroRoot: './src',
|
||||
pages: './src/pages',
|
||||
dist: './dist',
|
||||
public: './public',
|
||||
extensions: {
|
||||
|
|
|
@ -3,7 +3,7 @@ import type { ImportSpecifier, ImportDefaultSpecifier, ImportNamespaceSpecifier
|
|||
export interface AstroConfigRaw {
|
||||
dist: string;
|
||||
projectRoot: string;
|
||||
astroRoot: string;
|
||||
pages: string;
|
||||
public: string;
|
||||
jsx?: string;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ export interface AstroMarkdownOptions {
|
|||
export interface AstroConfig {
|
||||
dist: string;
|
||||
projectRoot: URL;
|
||||
astroRoot: URL;
|
||||
pages: URL;
|
||||
public: URL;
|
||||
renderers?: string[];
|
||||
/** Options for rendering markdown content */
|
||||
|
|
|
@ -41,9 +41,8 @@ function isRemote(url: string) {
|
|||
|
||||
/** The primary build action */
|
||||
export async function build(astroConfig: AstroConfig, logging: LogOptions = defaultLogging): Promise<0 | 1> {
|
||||
const { projectRoot, astroRoot } = astroConfig;
|
||||
const { projectRoot, pages: pagesRoot } = astroConfig;
|
||||
const dist = new URL(astroConfig.dist + '/', projectRoot);
|
||||
const pageRoot = new URL('./pages/', astroRoot);
|
||||
const buildState: BuildOutput = {};
|
||||
const depTree: BundleMap = {};
|
||||
const timer: Record<string, number> = {};
|
||||
|
@ -70,7 +69,7 @@ export async function build(astroConfig: AstroConfig, logging: LogOptions = defa
|
|||
* Source files are built in parallel and stored in memory. Most assets are also gathered here, too.
|
||||
*/
|
||||
timer.build = performance.now();
|
||||
const pages = await allPages(pageRoot);
|
||||
const pages = await allPages(pagesRoot);
|
||||
info(logging, 'build', yellow('! building pages...'));
|
||||
const release = trapWarn(); // Vue also console.warns, this silences it.
|
||||
await Promise.all(
|
||||
|
|
|
@ -22,9 +22,9 @@ export function getPageType(filepath: URL): 'collection' | 'static' {
|
|||
}
|
||||
|
||||
/** Build collection */
|
||||
export async function buildCollectionPage({ astroConfig, filepath, logging, mode, runtime, site, resolvePackageUrl, buildState }: PageBuildOptions): Promise<void> {
|
||||
const pagesPath = new URL('./pages/', astroConfig.astroRoot);
|
||||
const srcURL = filepath.pathname.replace(pagesPath.pathname, '/');
|
||||
export async function buildCollectionPage({ astroConfig, filepath, runtime, site, buildState }: PageBuildOptions): Promise<void> {
|
||||
const { pages: pagesRoot } = astroConfig;
|
||||
const srcURL = filepath.pathname.replace(pagesRoot.pathname, '/');
|
||||
const outURL = srcURL.replace(/\$([^.]+)\.astro$/, '$1');
|
||||
|
||||
const builtURLs = new Set<string>(); // !important: internal cache that prevents building the same URLs
|
||||
|
@ -89,8 +89,8 @@ export async function buildCollectionPage({ astroConfig, filepath, logging, mode
|
|||
|
||||
/** Build static page */
|
||||
export async function buildStaticPage({ astroConfig, buildState, filepath, runtime }: PageBuildOptions): Promise<void> {
|
||||
const pagesPath = new URL('./pages/', astroConfig.astroRoot);
|
||||
const url = filepath.pathname.replace(pagesPath.pathname, '/').replace(/(index)?\.(astro|md)$/, '');
|
||||
const { pages: pagesRoot } = astroConfig;
|
||||
const url = filepath.pathname.replace(pagesRoot.pathname, '/').replace(/(index)?\.(astro|md)$/, '');
|
||||
|
||||
// build page in parallel
|
||||
await Promise.all([
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import type { AstroConfig } from '../@types/astro';
|
||||
import { performance } from 'perf_hooks';
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { URL } from 'url';
|
||||
|
||||
|
@ -16,28 +17,43 @@ export function canonicalURL(url: string, base?: string): URL {
|
|||
/** Resolve final output URL */
|
||||
export function getDistPath(specifier: string, { astroConfig, srcPath }: { astroConfig: AstroConfig; srcPath: URL }): string {
|
||||
if (specifier[0] === '/') return specifier; // assume absolute URLs are correct
|
||||
const pagesDir = path.join(astroConfig.astroRoot.pathname, 'pages');
|
||||
const { pages: pagesRoot, projectRoot } = astroConfig;
|
||||
|
||||
const fileLoc = path.posix.join(path.posix.dirname(srcPath.pathname), specifier);
|
||||
const projectLoc = path.posix.relative(astroConfig.astroRoot.pathname, fileLoc);
|
||||
const fileLoc = new URL(specifier, srcPath);
|
||||
const projectLoc = fileLoc.pathname.replace(projectRoot.pathname, '');
|
||||
|
||||
const isPage = fileLoc.includes(pagesDir);
|
||||
const isPage = fileLoc.pathname.includes(pagesRoot.pathname);
|
||||
// if this lives above src/pages, return that URL
|
||||
if (isPage) {
|
||||
const [, publicURL] = projectLoc.split(pagesDir);
|
||||
const [, publicURL] = projectLoc.split(pagesRoot.pathname);
|
||||
return publicURL || '/index.html'; // if this is missing, this is the root
|
||||
}
|
||||
// otherwise, return /_astro/* url
|
||||
return '/_astro/' + projectLoc;
|
||||
}
|
||||
|
||||
/** Given a final output URL, guess at src path (may be inaccurate) */
|
||||
export function getSrcPath(url: string, { astroConfig }: { astroConfig: AstroConfig }): URL {
|
||||
if (url.startsWith('/_astro/')) {
|
||||
return new URL(url.replace(/^\/_astro\//, ''), astroConfig.astroRoot);
|
||||
/** Given a final output URL, guess at src path (may be inaccurate; only for non-pages) */
|
||||
export function getSrcPath(distURL: string, { astroConfig }: { astroConfig: AstroConfig }): URL {
|
||||
if (distURL.startsWith('/_astro/')) {
|
||||
return new URL('.' + distURL.replace(/^\/_astro\//, ''), astroConfig.projectRoot);
|
||||
} else if (distURL === '/index.html') {
|
||||
return new URL('./index.astro', astroConfig.pages);
|
||||
}
|
||||
let srcFile = url.replace(/^\//, '').replace(/\/index.html$/, '.astro');
|
||||
return new URL('./pages/' + srcFile, astroConfig.astroRoot);
|
||||
|
||||
const possibleURLs = [
|
||||
new URL('.' + distURL, astroConfig.public), // public asset
|
||||
new URL('.' + distURL.replace(/([^\/])+\/d+\/index.html/, '$$1.astro'), astroConfig.pages), // collection page
|
||||
new URL('.' + distURL.replace(/\/index\.html$/, '.astro'), astroConfig.pages), // page
|
||||
// TODO: Astro pages (this isn’t currently used for that lookup)
|
||||
];
|
||||
|
||||
// if this is in public/ or pages/, return that
|
||||
for (const possibleURL of possibleURLs) {
|
||||
if (fs.existsSync(possibleURL)) return possibleURL;
|
||||
}
|
||||
|
||||
// otherwise resolve relative to project
|
||||
return new URL('.' + distURL, astroConfig.projectRoot);
|
||||
}
|
||||
|
||||
/** Stop timer & format time for profiling */
|
||||
|
|
|
@ -141,14 +141,13 @@ const PlainExtensions = new Set(['.js', '.jsx', '.ts', '.tsx']);
|
|||
/** Generate Astro-friendly component import */
|
||||
function getComponentWrapper(_name: string, { url, importSpecifier }: ComponentInfo, opts: GetComponentWrapperOptions) {
|
||||
const { astroConfig, filename } = opts;
|
||||
const { astroRoot } = astroConfig;
|
||||
const currFileUrl = new URL(`file://${filename}`);
|
||||
const [name, kind] = _name.split(':');
|
||||
const getComponentUrl = () => {
|
||||
const componentExt = path.extname(url);
|
||||
const ext = PlainExtensions.has(componentExt) ? '.js' : `${componentExt}.js`;
|
||||
const outUrl = new URL(url, currFileUrl);
|
||||
return '/_astro/' + path.posix.relative(astroRoot.pathname, outUrl.pathname).replace(/\.[^.]+$/, ext);
|
||||
return '/_astro/' + outUrl.href.replace(astroConfig.projectRoot.href, '').replace(/\.[^.]+$/, ext);
|
||||
};
|
||||
const getComponentExport = () => {
|
||||
switch (importSpecifier.type) {
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
import type { Transformer } from '../../@types/transformer';
|
||||
import type { CompileOptions } from '../../@types/compiler';
|
||||
|
||||
import path from 'path';
|
||||
import { getAttrValue, setAttrValue } from '../../ast.js';
|
||||
|
||||
/** Transform <script type="module"> */
|
||||
export default function ({ compileOptions, filename }: { compileOptions: CompileOptions; filename: string; fileID: string }): Transformer {
|
||||
const { astroConfig } = compileOptions;
|
||||
const { astroRoot } = astroConfig;
|
||||
const fileUrl = new URL(`file://${filename}`);
|
||||
|
||||
return {
|
||||
|
@ -31,8 +29,7 @@ export default function ({ compileOptions, filename }: { compileOptions: Compile
|
|||
}
|
||||
|
||||
const srcUrl = new URL(src, fileUrl);
|
||||
const fromAstroRoot = path.posix.relative(astroRoot.pathname, srcUrl.pathname);
|
||||
const absoluteUrl = `/_astro/${fromAstroRoot}`;
|
||||
const absoluteUrl = `/_astro/${srcUrl.href.replace(astroConfig.projectRoot.href, '')}`;
|
||||
setAttrValue(node.attributes, 'src', absoluteUrl);
|
||||
},
|
||||
},
|
||||
|
|
|
@ -14,7 +14,7 @@ function validateConfig(config: any): void {
|
|||
if (typeof config !== 'object') throw new Error(`[config] Expected object, received ${typeof config}`);
|
||||
|
||||
// strings
|
||||
for (const key of ['projectRoot', 'astroRoot', 'dist', 'public']) {
|
||||
for (const key of ['projectRoot', 'pages', 'dist', 'public']) {
|
||||
if (config[key] !== undefined && config[key] !== null && typeof config[key] !== 'string') {
|
||||
throw new Error(`[config] ${key}: ${JSON.stringify(config[key])}\n Expected string, received ${type(config[key])}.`);
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ function configDefaults(userConfig?: any): any {
|
|||
const config: any = { ...(userConfig || {}) };
|
||||
|
||||
if (!config.projectRoot) config.projectRoot = '.';
|
||||
if (!config.astroRoot) config.astroRoot = './src';
|
||||
if (!config.pages) config.pages = './src/pages';
|
||||
if (!config.dist) config.dist = './dist';
|
||||
if (!config.public) config.public = './public';
|
||||
if (!config.devOptions) config.devOptions = {};
|
||||
|
@ -72,7 +72,7 @@ function normalizeConfig(userConfig: any, root: string): AstroConfig {
|
|||
|
||||
const fileProtocolRoot = `file://${root}/`;
|
||||
config.projectRoot = new URL(config.projectRoot + '/', fileProtocolRoot);
|
||||
config.astroRoot = new URL(config.astroRoot + '/', fileProtocolRoot);
|
||||
config.pages = new URL(config.pages + '/', fileProtocolRoot);
|
||||
config.public = new URL(config.public + '/', fileProtocolRoot);
|
||||
|
||||
return config as AstroConfig;
|
||||
|
|
|
@ -50,7 +50,7 @@ snowpackLogger.level = 'silent';
|
|||
/** Pass a URL to Astro to resolve and build */
|
||||
async function load(config: RuntimeConfig, rawPathname: string | undefined): Promise<LoadResult> {
|
||||
const { logging, backendSnowpackRuntime, frontendSnowpack } = config;
|
||||
const { astroRoot, buildOptions, devOptions } = config.astroConfig;
|
||||
const { pages: pagesRoot, buildOptions, devOptions } = config.astroConfig;
|
||||
|
||||
let origin = buildOptions.site ? new URL(buildOptions.site).origin : `http://localhost:${devOptions.port}`;
|
||||
const fullurl = new URL(rawPathname || '/', origin);
|
||||
|
@ -58,7 +58,7 @@ async function load(config: RuntimeConfig, rawPathname: string | undefined): Pro
|
|||
const reqPath = decodeURI(fullurl.pathname);
|
||||
info(logging, 'access', reqPath);
|
||||
|
||||
const searchResult = searchForPage(fullurl, astroRoot);
|
||||
const searchResult = searchForPage(fullurl, pagesRoot);
|
||||
if (searchResult.statusCode === 404) {
|
||||
try {
|
||||
const result = await frontendSnowpack.loadUrl(reqPath);
|
||||
|
@ -274,7 +274,7 @@ const DEFAULT_RENDERERS = ['@astrojs/renderer-svelte', '@astrojs/renderer-react'
|
|||
|
||||
/** Create a new Snowpack instance to power Astro */
|
||||
async function createSnowpack(astroConfig: AstroConfig, options: CreateSnowpackOptions) {
|
||||
const { projectRoot, astroRoot, renderers = DEFAULT_RENDERERS } = astroConfig;
|
||||
const { projectRoot, pages: pagesRoot, renderers = DEFAULT_RENDERERS } = astroConfig;
|
||||
const { env, mode, resolvePackageUrl, target } = options;
|
||||
|
||||
const internalPath = new URL('./frontend/', import.meta.url);
|
||||
|
@ -294,14 +294,12 @@ async function createSnowpack(astroConfig: AstroConfig, options: CreateSnowpackO
|
|||
};
|
||||
|
||||
const mountOptions = {
|
||||
[fileURLToPath(astroRoot)]: '/_astro',
|
||||
[fileURLToPath(pagesRoot)]: '/_astro/pages',
|
||||
...(existsSync(astroConfig.public) ? { [fileURLToPath(astroConfig.public)]: '/' } : {}),
|
||||
[fileURLToPath(internalPath)]: '/_astro_internal',
|
||||
[fileURLToPath(projectRoot)]: '/_astro', // must be last (greediest)
|
||||
};
|
||||
|
||||
if (existsSync(astroConfig.public)) {
|
||||
mountOptions[fileURLToPath(astroConfig.public)] = '/';
|
||||
}
|
||||
|
||||
// Tailwind: IDK what this does but it makes JIT work 🤷♂️
|
||||
if (astroConfig.devOptions.tailwindConfig) {
|
||||
(process.env as any).TAILWIND_DISABLE_TOUCH = true;
|
||||
|
|
|
@ -9,9 +9,9 @@ interface PageLocation {
|
|||
snowpackURL: string;
|
||||
}
|
||||
/** findAnyPage and return the _astro candidate for snowpack */
|
||||
function findAnyPage(candidates: Array<string>, astroRoot: URL): PageLocation | false {
|
||||
function findAnyPage(candidates: Array<string>, pagesRoot: URL): PageLocation | false {
|
||||
for (let candidate of candidates) {
|
||||
const url = new URL(`./pages/${candidate}`, astroRoot);
|
||||
const url = new URL(`./${candidate}`, pagesRoot);
|
||||
if (existsSync(url)) {
|
||||
return {
|
||||
fileURL: url,
|
||||
|
@ -39,14 +39,14 @@ type SearchResult =
|
|||
};
|
||||
|
||||
/** Given a URL, attempt to locate its source file (similar to Snowpack’s load()) */
|
||||
export function searchForPage(url: URL, astroRoot: URL): SearchResult {
|
||||
export function searchForPage(url: URL, pagesRoot: URL): SearchResult {
|
||||
const reqPath = decodeURI(url.pathname);
|
||||
const base = reqPath.substr(1);
|
||||
|
||||
// Try to find index.astro/md paths
|
||||
if (reqPath.endsWith('/')) {
|
||||
const candidates = [`${base}index.astro`, `${base}index.md`];
|
||||
const location = findAnyPage(candidates, astroRoot);
|
||||
const location = findAnyPage(candidates, pagesRoot);
|
||||
if (location) {
|
||||
return {
|
||||
statusCode: 200,
|
||||
|
@ -57,7 +57,7 @@ export function searchForPage(url: URL, astroRoot: URL): SearchResult {
|
|||
} else {
|
||||
// Try to find the page by its name.
|
||||
const candidates = [`${base}.astro`, `${base}.md`];
|
||||
let location = findAnyPage(candidates, astroRoot);
|
||||
let location = findAnyPage(candidates, pagesRoot);
|
||||
if (location) {
|
||||
return {
|
||||
statusCode: 200,
|
||||
|
@ -69,7 +69,7 @@ export function searchForPage(url: URL, astroRoot: URL): SearchResult {
|
|||
|
||||
// Try to find name/index.astro/md
|
||||
const candidates = [`${base}/index.astro`, `${base}/index.md`];
|
||||
const location = findAnyPage(candidates, astroRoot);
|
||||
const location = findAnyPage(candidates, pagesRoot);
|
||||
if (location) {
|
||||
return {
|
||||
statusCode: 301,
|
||||
|
@ -81,7 +81,7 @@ export function searchForPage(url: URL, astroRoot: URL): SearchResult {
|
|||
// Try and load collections (but only for non-extension files)
|
||||
const hasExt = !!path.extname(reqPath);
|
||||
if (!location && !hasExt) {
|
||||
const collection = loadCollection(reqPath, astroRoot);
|
||||
const collection = loadCollection(reqPath, pagesRoot);
|
||||
if (collection) {
|
||||
return {
|
||||
statusCode: 200,
|
||||
|
@ -109,8 +109,8 @@ export function searchForPage(url: URL, astroRoot: URL): SearchResult {
|
|||
}
|
||||
|
||||
/** load a collection route */
|
||||
function loadCollection(url: string, astroRoot: URL): { currentPage?: number; location: PageLocation } | undefined {
|
||||
const pages = glob('**/$*.astro', { cwd: path.join(fileURLToPath(astroRoot), 'pages'), filesOnly: true });
|
||||
function loadCollection(url: string, pagesRoot: URL): { currentPage?: number; location: PageLocation } | undefined {
|
||||
const pages = glob('**/$*.astro', { cwd: fileURLToPath(pagesRoot), filesOnly: true });
|
||||
for (const pageURL of pages) {
|
||||
const reqURL = new RegExp('^/' + pageURL.replace(/\$([^/]+)\.astro/, '$1') + '/?(.*)');
|
||||
const match = url.match(reqURL);
|
||||
|
@ -127,7 +127,7 @@ function loadCollection(url: string, astroRoot: URL): { currentPage?: number; lo
|
|||
}
|
||||
return {
|
||||
location: {
|
||||
fileURL: new URL(`./pages/${pageURL}`, astroRoot),
|
||||
fileURL: new URL(`./${pageURL}`, pagesRoot),
|
||||
snowpackURL: `/_astro/pages/${pageURL}.js`,
|
||||
},
|
||||
currentPage,
|
||||
|
|
|
@ -39,9 +39,9 @@ Markdown('Bundles client-side JS for prod', async (context) => {
|
|||
await context.build();
|
||||
|
||||
const complexHtml = await context.readFile('/complex/index.html');
|
||||
assert.match(complexHtml, `import("/_astro/components/Counter.js"`);
|
||||
assert.match(complexHtml, `import("/_astro/src/components/Counter.js"`);
|
||||
|
||||
const counterJs = await context.readFile('/_astro/components/Counter.js');
|
||||
const counterJs = await context.readFile('/_astro/src/components/Counter.js');
|
||||
assert.ok(counterJs, 'Counter.jsx is bundled for prod');
|
||||
});
|
||||
|
||||
|
|
|
@ -19,12 +19,12 @@ setup(StylesSSR, './fixtures/astro-styles-ssr');
|
|||
|
||||
StylesSSR('Has <link> tags', async ({ runtime }) => {
|
||||
const MUST_HAVE_LINK_TAGS = [
|
||||
'/_astro/components/ReactCSS.css',
|
||||
'/_astro/components/ReactModules.module.css',
|
||||
'/_astro/components/SvelteScoped.svelte.css',
|
||||
'/_astro/components/VueCSS.vue.css',
|
||||
'/_astro/components/VueModules.vue.css',
|
||||
'/_astro/components/VueScoped.vue.css',
|
||||
'/_astro/src/components/ReactCSS.css',
|
||||
'/_astro/src/components/ReactModules.module.css',
|
||||
'/_astro/src/components/SvelteScoped.svelte.css',
|
||||
'/_astro/src/components/VueCSS.vue.css',
|
||||
'/_astro/src/components/VueModules.vue.css',
|
||||
'/_astro/src/components/VueScoped.vue.css',
|
||||
];
|
||||
|
||||
const result = await runtime.load('/');
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export default {
|
||||
// projectRoot: '.', // Where to resolve all URLs relative to. Useful if you have a monorepo project.
|
||||
// astroRoot: './src', // Path to Astro components, pages, and data
|
||||
// pages: './src/pages', // Path to Astro components, pages, and data
|
||||
// dist: './dist', // When running `astro build`, path to final static output
|
||||
// public: './public', // A folder of static files Astro will copy to the root. Useful for favicons, images, and other files that don’t need processing.
|
||||
extensions: {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export default {
|
||||
// projectRoot: '.', // Where to resolve all URLs relative to. Useful if you have a monorepo project.
|
||||
// astroRoot: './src', // Path to Astro components, pages, and data
|
||||
// pages: './src/pages', // Path to Astro components, pages, and data
|
||||
// dist: './dist', // When running `astro build`, path to final static output
|
||||
// public: './public', // A folder of static files Astro will copy to the root. Useful for favicons, images, and other files that don’t need processing.
|
||||
extensions: {
|
||||
|
|
Loading…
Reference in a new issue