Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support parallel builds #11984

Merged
merged 28 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
900bc1c
支持并发生成
chaegumi Sep 13, 2024
1396c6e
feat: Add support parallel builds
chaegumi Sep 13, 2024
35d177e
feat: read concurrency config
chaegumi Sep 13, 2024
5c36939
changeset
chaegumi Sep 13, 2024
a92127c
fix: Explicit undefined is unnecessary on an optional parameter
chaegumi Sep 13, 2024
fe15f3e
Merge remote-tracking branch 'origin/main' into concurrencybuild
chaegumi Sep 13, 2024
7272fee
pnpm-lock.yaml rebuild
chaegumi Sep 13, 2024
004583e
fix: add innerPrevTimeEnd
chaegumi Sep 14, 2024
43fa00a
fix: modification time calculation
chaegumi Sep 14, 2024
4d4113b
Merge remote-tracking branch 'origin/main' into concurrencybuild
chaegumi Sep 19, 2024
95bab56
update pnpm-lock.yaml
chaegumi Sep 19, 2024
bae0e4e
Merge branch 'main' into pr/chaegumi/11984 [skip-ci]
bluwy Sep 19, 2024
4f09a93
Rewrite with p-limit
chaegumi Sep 20, 2024
3e26b4c
Merge branch 'concurrencybuild' of github.com:chaegumi/astro into con…
chaegumi Sep 20, 2024
c788b17
update
bluwy Oct 1, 2024
c89246b
Merge branch 'main' into pr/chaegumi/11984
bluwy Oct 1, 2024
1ae82ca
clean
bluwy Oct 1, 2024
b2e1aa0
Update changeset
bluwy Oct 1, 2024
1ee8cba
typo [skip ci]
bluwy Oct 1, 2024
2a88d1d
Apply suggestions from code review
ematipico Oct 8, 2024
175b29d
Apply suggestions from code review
ematipico Oct 8, 2024
fb6ba54
Update packages/astro/src/core/config/schema.ts
ematipico Oct 8, 2024
5f9e6c5
formatting
ematipico Oct 8, 2024
65f5605
Merge remote-tracking branch 'origin/main' into concurrencybuild
ematipico Oct 8, 2024
d6ebd90
merge main and update the lock file
ematipico Oct 8, 2024
caff1c3
Update packages/astro/src/@types/astro.ts
ematipico Oct 8, 2024
92c5953
Update packages/astro/src/@types/astro.ts
ematipico Oct 8, 2024
775b042
Apply suggestions from code review
ematipico Oct 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .changeset/ten-emus-heal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
'astro': minor
---

Adds the `build.concurreny` to specify the number of pages to build in parallel. In most cases, you should stick with the default value of `1`,
and batch or cache long running tasks like fetch calls or data access to improve the overall rendering time.

Use this option only if the refactors are not possible. If the number is set too high, the page rendering
may slow down due to insufficient memory resources and because JS is single-threaded.

In the future, Astro may reuse this option to render pages concurrently with multiple threads.
bluwy marked this conversation as resolved.
Show resolved Hide resolved
ematipico marked this conversation as resolved.
Show resolved Hide resolved

```js
// astro.config.mjs
import { defineConfig } from 'astro';

export default defineConfig({
build: {
concurrency: 2,
},
});
```
23 changes: 23 additions & 0 deletions packages/astro/src/@types/astro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,29 @@ export interface AstroUserConfig {
* ```
*/
inlineStylesheets?: 'always' | 'auto' | 'never';
/**
* @docs
* @name build.concurrency
* @type {boolean}
ematipico marked this conversation as resolved.
Show resolved Hide resolved
* @default `1`
* @description
ematipico marked this conversation as resolved.
Show resolved Hide resolved
* The number of pages to build in parallel. In most cases, you should stick with the default value of `1`,
* and batch or cache long running tasks like fetch calls or data access to improve the overall rendering time.
*
* Use this option only if the refactors are not possible. If the number is set too high, the page rendering
* may slow down due to insufficient memory resources and because JS is single-threaded.
ematipico marked this conversation as resolved.
Show resolved Hide resolved
*
* In the future, Astro may reuse this option to render pages concurrently with multiple threads.
*
bluwy marked this conversation as resolved.
Show resolved Hide resolved
* ```js
* {
* build: {
* concurrency: 1
ematipico marked this conversation as resolved.
Show resolved Hide resolved
* }
* }
* ```
ematipico marked this conversation as resolved.
Show resolved Hide resolved
*/
concurrency?: number;
};

/**
Expand Down
69 changes: 50 additions & 19 deletions packages/astro/src/core/build/generate.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from 'node:fs';
import os from 'node:os';
import { bgGreen, black, blue, bold, dim, green, magenta, red } from 'kleur/colors';
import PLimit from 'p-limit';
import PQueue from 'p-queue';
import type {
AstroConfig,
Expand Down Expand Up @@ -198,35 +199,65 @@ async function generatePage(
styles,
mod: pageModule,
};

async function generatePathWithLogs(
path: string,
route: RouteData,
index: number,
paths: string[],
isConcurrent: boolean,
) {
const timeStart = performance.now();
pipeline.logger.debug('build', `Generating: ${path}`);

const filePath = getOutputFilename(config, path, pageData.route.type);
const lineIcon =
(index === paths.length - 1 && !isConcurrent) || paths.length === 1 ? '└─' : '├─';

// Log the rendering path first if not concurrent. We'll later append the time taken to render.
// We skip if it's concurrent as the logs may overlap
if (!isConcurrent) {
logger.info(null, ` ${blue(lineIcon)} ${dim(filePath)}`, false);
}

await generatePath(path, pipeline, generationOptions, route);

const timeEnd = performance.now();
const isSlow = timeEnd - timeStart > THRESHOLD_SLOW_RENDER_TIME_MS;
const timeIncrease = (isSlow ? red : dim)(`(+${getTimeStat(timeStart, timeEnd)})`);

if (isConcurrent) {
logger.info(null, ` ${blue(lineIcon)} ${dim(filePath)} ${timeIncrease}`);
} else {
logger.info('SKIP_FORMAT', ` ${timeIncrease}`);
}
}

// Now we explode the routes. A route render itself, and it can render its fallbacks (i18n routing)
for (const route of eachRouteInRouteData(pageData)) {
const icon =
route.type === 'page' || route.type === 'redirect' || route.type === 'fallback'
? green('▶')
: magenta('λ');
logger.info(null, `${icon} ${getPrettyRouteName(route)}`);

// Get paths for the route, calling getStaticPaths if needed.
const paths = await getPathsForRoute(route, pageModule, pipeline, builtPaths);
let timeStart = performance.now();
let prevTimeEnd = timeStart;
for (let i = 0; i < paths.length; i++) {
const path = paths[i];
pipeline.logger.debug('build', `Generating: ${path}`);
const filePath = getOutputFilename(config, path, pageData.route.type);
const lineIcon = i === paths.length - 1 ? '└─' : '├─';
logger.info(null, ` ${blue(lineIcon)} ${dim(filePath)}`, false);
await generatePath(path, pipeline, generationOptions, route);
const timeEnd = performance.now();
const timeChange = getTimeStat(prevTimeEnd, timeEnd);
const timeIncrease = `(+${timeChange})`;
let timeIncreaseLabel;
if (timeEnd - prevTimeEnd > THRESHOLD_SLOW_RENDER_TIME_MS) {
timeIncreaseLabel = red(timeIncrease);
} else {
timeIncreaseLabel = dim(timeIncrease);

// Generate each paths
if (config.build.concurrency > 1) {
const limit = PLimit(config.build.concurrency);
const promises: Promise<void>[] = [];
for (let i = 0; i < paths.length; i++) {
const path = paths[i];
promises.push(limit(() => generatePathWithLogs(path, route, i, paths, true)));
}
await Promise.allSettled(promises);
} else {
for (let i = 0; i < paths.length; i++) {
const path = paths[i];
await generatePathWithLogs(path, route, i, paths, false);
}
logger.info('SKIP_FORMAT', ` ${timeIncreaseLabel}`);
prevTimeEnd = timeEnd;
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions packages/astro/src/core/config/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export const ASTRO_CONFIG_DEFAULTS = {
serverEntry: 'entry.mjs',
redirects: true,
inlineStylesheets: 'auto',
concurrency: 1,
},
image: {
service: { entrypoint: 'astro/assets/services/sharp', config: {} },
Expand Down Expand Up @@ -186,6 +187,7 @@ export const AstroConfigSchema = z.object({
.enum(['always', 'auto', 'never'])
.optional()
.default(ASTRO_CONFIG_DEFAULTS.build.inlineStylesheets),
concurrency: z.number().min(1).optional().default(ASTRO_CONFIG_DEFAULTS.build.concurrency),
ematipico marked this conversation as resolved.
Show resolved Hide resolved
})
.default({}),
server: z.preprocess(
Expand Down Expand Up @@ -619,6 +621,7 @@ export function createRelativeSchema(cmd: string, fileProtocolRoot: string) {
.enum(['always', 'auto', 'never'])
.optional()
.default(ASTRO_CONFIG_DEFAULTS.build.inlineStylesheets),
concurrency: z.number().optional().default(ASTRO_CONFIG_DEFAULTS.build.concurrency),
ematipico marked this conversation as resolved.
Show resolved Hide resolved
})
.optional()
.default({}),
Expand Down
Loading
Loading