e9a77d8619
* wip: fix nested islands
* fix: improve hydration for dynamic content
* chore: fix bundle-size script for new files
* chore: allow-list client:* directive files
* fix(#3362): fix client:only behavior for React, Vue, Solid
* test: add client-only e2e test
* chore: update lockfile
* test: fix e2e tests
* test: add framework nesting e2e tests
* Update packages/astro/src/runtime/client/events.ts
Co-authored-by: Matthew Phillips <matthew@skypack.dev>
* chore: add changeset
* fix(preact): ignore hydrate roots
* chore: remove `ssr` check in integrations
* Revert "chore: remove `ssr` check in integrations"
This reverts commit ba27eaae55
.
* chore: add changeset
Co-authored-by: Matthew Phillips <matthew@skypack.dev>
83 lines
3.2 KiB
JavaScript
83 lines
3.2 KiB
JavaScript
import { build } from 'esbuild';
|
|
import { existsSync } from 'fs';
|
|
|
|
const CLIENT_RUNTIME_PATH = 'packages/astro/src/runtime/client/';
|
|
|
|
function formatBytes(bytes, decimals = 2) {
|
|
if (bytes === 0) return '0 B';
|
|
|
|
const k = 1024;
|
|
const dm = decimals < 0 ? 0 : decimals;
|
|
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
|
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
|
}
|
|
|
|
export default async function checkBundleSize({ github, context }) {
|
|
const PR_NUM = context.payload.pull_request.number;
|
|
const SHA = context.payload.pull_request.head.sha;
|
|
|
|
const { data: files } = await github.rest.pulls.listFiles({
|
|
...context.repo,
|
|
pull_number: PR_NUM,
|
|
});
|
|
const clientRuntimeFiles = files.filter(({ filename }) => filename.startsWith(CLIENT_RUNTIME_PATH));
|
|
if (clientRuntimeFiles.length === 0) return;
|
|
|
|
const table = [
|
|
'| File | Old Size | New Size | Change |',
|
|
'| ---- | -------- | -------- | ------ |',
|
|
];
|
|
const output = await bundle(clientRuntimeFiles);
|
|
|
|
for (let [filename, { oldSize, newSize, sourceFile }] of Object.entries(output)) {
|
|
filename = ['idle', 'load', 'media', 'only', 'visible'].includes(filename) ? `client:${filename}` : filename;
|
|
const prefix = (newSize - oldSize) === 0 ? '' : (newSize - oldSize) > 0 ? '+ ' : '- ';
|
|
const change = `${prefix}${formatBytes(newSize - oldSize)}`;
|
|
table.push(`| [\`${filename}\`](https://github.com/${context.repo.owner}/${context.repo.repo}/tree/${context.payload.pull_request.head.ref}/${sourceFile}) | ${formatBytes(oldSize)} | ${formatBytes(newSize)} | ${change} |`);
|
|
}
|
|
|
|
const { data: comments } = await github.rest.issues.listComments({
|
|
...context.repo,
|
|
issue_number: PR_NUM
|
|
})
|
|
const comment = comments.find(comment => comment.user.login === 'github-actions[bot]' && comment.body.includes('Bundle Size Check'));
|
|
const method = comment ? 'updateComment' : 'createComment';
|
|
const payload = comment ? { comment_id: comment.id } : { issue_number: PR_NUM };
|
|
await github.rest.issues[method]({
|
|
...context.repo,
|
|
...payload,
|
|
body: `### ⚖️ Bundle Size Check
|
|
|
|
Latest commit: ${SHA}
|
|
|
|
${table.join('\n')}`,
|
|
});
|
|
}
|
|
|
|
async function bundle(files) {
|
|
|
|
const { metafile } = await build({
|
|
entryPoints: [...files.map(({ filename }) => filename), ...files.map(({ filename }) => `main/${filename}`).filter(f => existsSync(f))],
|
|
bundle: true,
|
|
minify: true,
|
|
sourcemap: false,
|
|
target: ['es2018'],
|
|
outdir: 'out',
|
|
metafile: true,
|
|
})
|
|
|
|
return Object.entries(metafile.outputs).reduce((acc, [filename, info]) => {
|
|
filename = filename.slice('out/'.length);
|
|
if (filename.startsWith('main/')) {
|
|
filename = filename.slice('main/'.length).replace(CLIENT_RUNTIME_PATH, '').replace('.js', '');
|
|
const oldSize = info.bytes;
|
|
return Object.assign(acc, { [filename]: Object.assign(acc[filename] ?? { oldSize: 0, newSize: 0 }, { oldSize }) });
|
|
}
|
|
filename = filename.replace(CLIENT_RUNTIME_PATH, '').replace('.js', '');
|
|
const newSize = info.bytes;
|
|
return Object.assign(acc, { [filename]: Object.assign(acc[filename] ?? { oldSize: 0, newSize: 0 }, { newSize, sourceFile: Object.keys(info.inputs).find(src => src.endsWith('.ts')) }) });
|
|
}, {});
|
|
}
|