summaryrefslogtreecommitdiff
path: root/src/build.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/build.ts')
-rw-r--r--src/build.ts112
1 files changed, 82 insertions, 30 deletions
diff --git a/src/build.ts b/src/build.ts
index 32b8bcc84..dccc432d8 100644
--- a/src/build.ts
+++ b/src/build.ts
@@ -1,34 +1,65 @@
import type { AstroConfig } from './@types/astro';
-import { defaultLogOptions, LogOptions } from './logger';
+import type { LogOptions } from './logger';
+import type { LoadResult } from './runtime';
-import { loadConfiguration, startServer as startSnowpackServer, build as snowpackBuild } from 'snowpack';
-import { promises as fsPromises } from 'fs';
+import { existsSync, promises as fsPromises } from 'fs';
import { relative as pathRelative } from 'path';
+import {fdir} from 'fdir';
import { defaultLogDestination, error } from './logger.js';
import { createRuntime } from './runtime.js';
+import { bundle, collectDynamicImports } from './build/bundle.js';
+import { collectStatics } from './build/static.js';
-const { mkdir, readdir, stat, writeFile } = fsPromises;
+const { mkdir, readdir, readFile, stat, writeFile } = fsPromises;
const logging: LogOptions = {
level: 'debug',
dest: defaultLogDestination,
};
-async function* allPages(root: URL): AsyncGenerator<URL, void, unknown> {
+async function* recurseFiles(root: URL): AsyncGenerator<URL, void, unknown> {
for (const filename of await readdir(root)) {
const fullpath = new URL(filename, root);
const info = await stat(fullpath);
if (info.isDirectory()) {
- yield* allPages(new URL(fullpath + '/'));
+ yield* recurseFiles(new URL(fullpath + '/'));
} else {
- if (/\.(astro|md)$/.test(fullpath.pathname)) {
- yield fullpath;
- }
+ yield fullpath;
}
}
}
+async function allPages(root: URL) {
+ const api = new fdir().filter(p => /\.(astro|md)$/.test(p))
+ .withFullPaths().crawl(root.pathname);
+ const files = await api.withPromise();
+ return files as string[];
+}
+
+function mergeSet(a: Set<string>, b: Set<string>) {
+ for(let str of b) {
+ a.add(str);
+ }
+ return a;
+}
+
+async function writeFilep(outPath: URL, bytes: string | Buffer, encoding: 'utf-8' | null) {
+ const outFolder = new URL('./', outPath);
+ await mkdir(outFolder, { recursive: true });
+ await writeFile(outPath, bytes, encoding || 'binary');
+}
+
+async function writeResult(result: LoadResult, outPath: URL, encoding: null | 'utf-8') {
+ if(result.statusCode !== 200) {
+ error(logging, 'build', result.error || result.statusCode);
+ //return 1;
+ } else {
+ const bytes = result.contents;
+ await writeFilep(outPath, bytes, encoding);
+ }
+}
+
export async function build(astroConfig: AstroConfig): Promise<0 | 1> {
const { projectRoot, astroRoot } = astroConfig;
const pageRoot = new URL('./pages/', astroRoot);
@@ -39,39 +70,60 @@ export async function build(astroConfig: AstroConfig): Promise<0 | 1> {
dest: defaultLogDestination,
};
- const runtime = await createRuntime(astroConfig, { logging: runtimeLogging, env: 'build' });
- const { snowpackConfig } = runtime.runtimeConfig;
-
- try {
- const result = await snowpackBuild({
- config: snowpackConfig,
- lockfile: null,
- });
- } catch (err) {
- error(logging, 'build', err);
- return 1;
- }
+ const runtime = await createRuntime(astroConfig, { logging: runtimeLogging });
+ const { runtimeConfig } = runtime;
+ const { snowpack } = runtimeConfig;
+ const resolve = (pkgName: string) => snowpack.getUrlForPackage(pkgName)
- for await (const filepath of allPages(pageRoot)) {
+ const imports = new Set<string>();
+ const statics = new Set<string>();
+
+ for (const pathname of await allPages(pageRoot)) {
+ const filepath = new URL(`file://${pathname}`);
const rel = pathRelative(astroRoot.pathname + '/pages', filepath.pathname); // pages/index.astro
const pagePath = `/${rel.replace(/\.(astro|md)/, '')}`;
try {
- const outPath = new URL('./' + rel.replace(/\.(astro|md)/, '.html'), dist);
- const outFolder = new URL('./', outPath);
+ let relPath = './' + rel.replace(/\.(astro|md)$/, '.html');
+ if(!relPath.endsWith('index.html')) {
+ relPath = relPath.replace(/\.html$/, '/index.html');
+ }
+
+ const outPath = new URL(relPath, dist);
const result = await runtime.load(pagePath);
- if (result.statusCode !== 200) {
- error(logging, 'generate', result.error || result.statusCode);
- //return 1;
- } else {
- await mkdir(outFolder, { recursive: true });
- await writeFile(outPath, result.contents, 'utf-8');
+ await writeResult(result, outPath, 'utf-8');
+ if(result.statusCode === 200) {
+ mergeSet(statics, collectStatics(result.contents.toString('utf-8')));
}
} catch (err) {
error(logging, 'generate', err);
return 1;
}
+
+ mergeSet(imports, await collectDynamicImports(filepath, astroConfig, resolve));
+ }
+
+ await bundle(imports, {dist, runtime, astroConfig});
+
+ for(let url of statics) {
+ const outPath = new URL('.' + url, dist);
+ const result = await runtime.load(url);
+
+ await writeResult(result, outPath, null);
+ }
+
+ if(existsSync(astroConfig.public)) {
+ const pub = astroConfig.public;
+ const publicFiles = (await new fdir().withFullPaths().crawl(pub.pathname).withPromise()) as string[];
+ for(const filepath of publicFiles) {
+ const fileUrl = new URL(`file://${filepath}`)
+ const rel = pathRelative(pub.pathname, fileUrl.pathname);
+ const outUrl = new URL('./' + rel, dist);
+
+ const bytes = await readFile(fileUrl);
+ await writeFilep(outUrl, bytes, null);
+ }
}
await runtime.shutdown();