chore: Refactor build output type (#19)

This commit is contained in:
Aaron
2023-07-01 13:58:44 -05:00
committed by GitHub
parent f02abc5227
commit 8be53efd24
5 changed files with 91 additions and 37 deletions
+32 -23
View File
@@ -1,6 +1,11 @@
import * as vite from 'vite';
import { BuildOutput, Entrypoint, InternalConfig } from '../types';
import { groupEntrypoints } from '../utils/groupEntrypoints';
import {
BuildOutput,
BuildStepOutput,
Entrypoint,
EntrypointGroup,
InternalConfig,
} from '../types';
import * as plugins from '../vite-plugins';
import { removeEmptyDirs } from '../utils/removeEmptyDirs';
import { getEntrypointBundlePath } from '../utils/entrypoints';
@@ -9,25 +14,22 @@ import fs from 'fs-extra';
import { dirname, resolve } from 'path';
export async function buildEntrypoints(
entrypoints: Entrypoint[],
groups: EntrypointGroup[],
config: InternalConfig,
): Promise<BuildOutput> {
const groups = groupEntrypoints(entrypoints);
const outputs: BuildOutput[] = [];
): Promise<Omit<BuildOutput, 'manifest'>> {
const steps: BuildStepOutput[] = [];
for (const group of groups) {
const output = Array.isArray(group)
const step = Array.isArray(group)
? await buildMultipleEntrypoints(group, config)
: await buildSingleEntrypoint(group, config);
outputs.push(output);
steps.push(step);
}
const publicOutput = await copyPublicDirectory(config);
outputs.push(publicOutput);
const publicAssets = await copyPublicDirectory(config);
// Remove any empty directories from moving outputs around
await removeEmptyDirs(config.outDir);
return outputs.flat();
return { publicAssets, steps };
}
/**
@@ -36,7 +38,7 @@ export async function buildEntrypoints(
async function buildSingleEntrypoint(
entrypoint: Entrypoint,
config: InternalConfig,
): Promise<BuildOutput> {
): Promise<BuildStepOutput> {
// Should this entrypoint be wrapped by the vite-plugins/virtualEntrypoint plugin?
const isVirtual = ['background', 'content-script'].includes(entrypoint.type);
const entry = isVirtual
@@ -74,7 +76,10 @@ async function buildSingleEntrypoint(
) as vite.InlineConfig;
const result = await vite.build(entryConfig);
return getBuildOutput(result);
return {
entrypoints: entrypoint,
chunks: getBuildOutputChunks(result),
};
}
/**
@@ -83,7 +88,7 @@ async function buildSingleEntrypoint(
async function buildMultipleEntrypoints(
entrypoints: Entrypoint[],
config: InternalConfig,
): Promise<BuildOutput> {
): Promise<BuildStepOutput> {
const multiPage: vite.InlineConfig = {
plugins: [plugins.multipageMove(entrypoints, config)],
build: {
@@ -110,12 +115,15 @@ async function buildMultipleEntrypoints(
) as vite.InlineConfig;
const result = await vite.build(entryConfig);
return getBuildOutput(result);
return {
entrypoints,
chunks: getBuildOutputChunks(result),
};
}
function getBuildOutput(
function getBuildOutputChunks(
result: Awaited<ReturnType<typeof vite.build>>,
): BuildOutput {
): BuildStepOutput['chunks'] {
if ('on' in result) throw Error('wxt does not support vite watch mode.');
if (Array.isArray(result)) return result.flatMap(({ output }) => output);
return result.output;
@@ -123,19 +131,19 @@ function getBuildOutput(
async function copyPublicDirectory(
config: InternalConfig,
): Promise<BuildOutput> {
if (!(await fs.exists(config.publicDir))) return [];
): Promise<BuildOutput['publicAssets']> {
const publicAssets: BuildOutput['publicAssets'] = [];
if (!(await fs.exists(config.publicDir))) return publicAssets;
const files = await glob('**/*', { cwd: config.publicDir });
const outputs: BuildOutput = [];
for (const file of files) {
const srcPath = resolve(config.publicDir, file);
const outPath = resolve(config.outDir, file);
await fs.ensureDir(dirname(outPath));
await fs.copyFile(srcPath, outPath);
outputs.push({
publicAssets.push({
type: 'asset',
fileName: file,
name: file,
@@ -143,5 +151,6 @@ async function copyPublicDirectory(
source: await fs.readFile(srcPath),
});
}
return outputs;
return publicAssets;
}
+4 -1
View File
@@ -9,7 +9,10 @@ export async function printBuildSummary(
output: BuildOutput,
config: InternalConfig,
) {
const chunks = output.sort((l, r) => {
const chunks = [
...output.steps.flatMap((step) => step.chunks),
...output.publicAssets,
].sort((l, r) => {
const lWeight =
CHUNK_SORT_WEIGHTS[l.fileName] ??
CHUNK_SORT_WEIGHTS[extname(l.fileName)] ??
+11 -1
View File
@@ -1,6 +1,7 @@
import * as vite from 'vite';
import { Manifest } from 'webextension-polyfill';
import { UnimportOptions } from 'unimport';
import { EntrypointGroup } from '.';
export interface InlineConfig {
root?: string;
@@ -29,7 +30,16 @@ export interface WxtInlineViteConfig
build?: Omit<vite.BuildOptions, 'outDir'>;
}
export type BuildOutput = (vite.Rollup.OutputChunk | vite.Rollup.OutputAsset)[];
export interface BuildOutput {
manifest: Manifest.WebExtensionManifest;
publicAssets: vite.Rollup.OutputAsset[];
steps: BuildStepOutput[];
}
export interface BuildStepOutput {
entrypoints: EntrypointGroup;
chunks: (vite.Rollup.OutputChunk | vite.Rollup.OutputAsset)[];
}
export interface WxtDevServer extends vite.ViteDevServer {
logger: Logger;
+7 -5
View File
@@ -29,7 +29,7 @@ export async function writeManifest(
await fs.ensureDir(config.outDir);
await fs.writeFile(resolve(config.outDir, 'manifest.json'), str, 'utf-8');
output.unshift({
output.publicAssets.unshift({
type: 'asset',
fileName: 'manifest.json',
name: 'manifest',
@@ -43,7 +43,7 @@ export async function writeManifest(
*/
export async function generateMainfest(
entrypoints: Entrypoint[],
buildOutput: BuildOutput,
buildOutput: Omit<BuildOutput, 'manifest'>,
config: InternalConfig,
): Promise<Manifest.WebExtensionManifest> {
const pkg = await getPackageJson(config);
@@ -100,7 +100,7 @@ function simplifyVersion(versionName: string): string {
function addEntrypoints(
manifest: Manifest.WebExtensionManifest,
entrypoints: Entrypoint[],
buildOutput: BuildOutput,
buildOutput: Omit<BuildOutput, 'manifest'>,
config: InternalConfig,
): void {
const entriesByType = entrypoints.reduce<
@@ -351,12 +351,14 @@ function addDevModeCsp(
*/
function getContentScriptCssFiles(
contentScripts: ContentScriptEntrypoint[],
buildOutput: BuildOutput,
buildOutput: Omit<BuildOutput, 'manifest'>,
): string[] | undefined {
const css: string[] = [];
const allChunks = buildOutput.steps.flatMap((step) => step.chunks);
contentScripts.forEach((script) => {
const relatedCss = buildOutput.find(
const relatedCss = allChunks.find(
(chunk) => chunk.fileName === `assets/${script.name}.css`,
);
if (relatedCss) css.push(relatedCss.fileName);
+37 -7
View File
@@ -3,6 +3,7 @@ import {
WxtDevServer,
InlineConfig,
InternalConfig,
EntrypointGroup,
} from './core/types';
import { getInternalConfig } from './core/utils/getInternalConfig';
import { findEntrypoints } from './core/build/findEntrypoints';
@@ -16,6 +17,8 @@ import * as vite from 'vite';
import { findOpenPort } from './core/utils/findOpenPort';
import { formatDuration } from './core/utils/formatDuration';
import { createWebExtRunner } from './core/runners/createWebExtRunner';
import { groupEntrypoints } from './core/utils/groupEntrypoints';
import { Manifest } from 'webextension-polyfill';
export { version } from '../package.json';
export * from './core/types/external';
@@ -90,14 +93,9 @@ async function buildInternal(config: InternalConfig): Promise<BuildOutput> {
await fs.rm(config.outDir, { recursive: true, force: true });
await fs.ensureDir(config.outDir);
// Build
const entrypoints = await findEntrypoints(config);
await generateTypesDir(entrypoints, config);
const output = await buildEntrypoints(entrypoints, config);
// Write manifest
const manifest = await generateMainfest(entrypoints, output, config);
await writeManifest(manifest, output, config);
const groups = groupEntrypoints(entrypoints);
const { output } = await rebuild(config, groups);
// Post-build
config.logger.success(
@@ -107,3 +105,35 @@ async function buildInternal(config: InternalConfig): Promise<BuildOutput> {
return output;
}
export async function rebuild(
config: InternalConfig,
entrypointGroups: EntrypointGroup[],
existingOutput: Omit<BuildOutput, 'manifest'> = {
steps: [],
publicAssets: [],
},
): Promise<{ output: BuildOutput; manifest: Manifest.WebExtensionManifest }> {
// Build
const allEntrypoints = await findEntrypoints(config);
await generateTypesDir(allEntrypoints, config);
const buildOutput = await buildEntrypoints(entrypointGroups, config);
const manifest = await generateMainfest(allEntrypoints, buildOutput, config);
const output: BuildOutput = {
manifest,
...buildOutput,
};
// Write manifest
await writeManifest(manifest, output, config);
return {
output: {
manifest,
steps: [...existingOutput.steps, ...output.steps],
publicAssets: [...existingOutput.publicAssets, ...output.publicAssets],
},
manifest,
};
}