Skip to content

Commit

Permalink
feat: init optimizer submodule
Browse files Browse the repository at this point in the history
  • Loading branch information
adamdbradley committed Jul 17, 2021
1 parent 107f525 commit d07ff46
Show file tree
Hide file tree
Showing 17 changed files with 1,142 additions and 0 deletions.
15 changes: 15 additions & 0 deletions src/optimizer/api-extractor.json
@@ -0,0 +1,15 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"extends": "../api-extractor.json",
"mainEntryPointFilePath": "<projectFolder>/dist-dev/tsc-out/src/optimizer/index.d.ts",
"apiReport": {
"enabled": true,
"reportFileName": "api.md",
"reportFolder": "<projectFolder>/src/optimizer/",
"reportTempFolder": "<projectFolder>/dist-dev/api-extractor/optimizer/"
},
"dtsRollup": {
"enabled": true,
"untrimmedFilePath": "<projectFolder>/dist-dev/@builder.io-qwik/optimizer.d.ts"
}
}
118 changes: 118 additions & 0 deletions src/optimizer/api.md
@@ -0,0 +1,118 @@
## API Report File for "@builder.io/qwik"

> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import type { BuildOptions } from 'esbuild';

// @alpha (undocumented)
export function createClientEsbuildOptions(optimizer: Optimizer): Promise<any>;

// @alpha (undocumented)
export function createEsbuilder(opts: {
outDir: string;
clientOpts?: BuildOptions;
serverOpts?: BuildOptions;
}): {
build: () => Promise<EsbuildResult>;
dispose: () => void;
};

// @alpha (undocumented)
export function createServerEsbuildOptions(optimizer: Optimizer): Promise<any>;

// @alpha
export function createTimer(): () => number;

// @alpha
export function getQwikLoaderScript(opts?: { events?: string[]; debug?: boolean }): string;

// @alpha
export class Optimizer {
// Warning: (ae-forgotten-export) The symbol "OptimizerOptions" needs to be exported by the entry point index.d.ts
constructor(opts?: OptimizerOptions);
// (undocumented)
enableCache(useCache: boolean): void;
// (undocumented)
getBaseUrl(): string;
// Warning: (ae-forgotten-export) The symbol "EntryPointOptions" needs to be exported by the entry point index.d.ts
//
// (undocumented)
getEntryInputs(opts: EntryPointOptions): string[];
// (undocumented)
getMode(): Mode;
// (undocumented)
getRootDir(): string;
// (undocumented)
getSourceMapOption(): SourceMapOption;
// (undocumented)
getTsconfig(): Promise<any>;
// (undocumented)
getTsconfigSync(): any;
// (undocumented)
getTypeScript(): Promise<any>;
// (undocumented)
getTypeScriptSync(): any;
// (undocumented)
isCacheEnabled(): boolean;
// (undocumented)
isDev(): boolean;
// (undocumented)
postBuild(outFile: OutputFile): OutputFile;
// Warning: (ae-forgotten-export) The symbol "ResolveModuleOptions" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "ResolveModuleResult" needs to be exported by the entry point index.d.ts
//
// (undocumented)
resolveModuleSync(opts: ResolveModuleOptions): ResolveModuleResult;
// (undocumented)
setBaseUrl(baseUrl: string): void;
// (undocumented)
setEntryInputs(entryInputs: string[]): void;
// Warning: (ae-forgotten-export) The symbol "Mode" needs to be exported by the entry point index.d.ts
//
// (undocumented)
setMode(mode: Mode): void;
// (undocumented)
setRootDir(rootDir: string): void;
// Warning: (ae-forgotten-export) The symbol "SourceMapOption" needs to be exported by the entry point index.d.ts
//
// (undocumented)
setSourceMapOption(sourceMapOpt: SourceMapOption): void;
// (undocumented)
setTsconfig(tsconfig: any): void;
// (undocumented)
setTypeScript(ts: any): void;
// Warning: (ae-forgotten-export) The symbol "TransformModuleOptions" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "TransformModuleResult" needs to be exported by the entry point index.d.ts
//
// (undocumented)
transformModule(opts: TransformModuleOptions): Promise<TransformModuleResult>;
// (undocumented)
transformModuleSync(opts: TransformModuleOptions): TransformModuleResult;
}

// @public (undocumented)
export interface OutputFile {
// (undocumented)
path: string;
// Warning: (ae-forgotten-export) The symbol "OutputPlatform" needs to be exported by the entry point index.d.ts
//
// (undocumented)
platform?: OutputPlatform;
// (undocumented)
text: string;
}

// @public
export function writeOutput(opts: {
dir: string;
files: OutputFile[];
emptyDir?: boolean;
}): Promise<void>;

// Warnings were encountered during analysis:
//
// dist-dev/tsc-out/src/optimizer/esbuild/builder.d.ts:11:5 - (ae-forgotten-export) The symbol "EsbuildResult" needs to be exported by the entry point index.d.ts

// (No @packageDocumentation comment for this package)
```
162 changes: 162 additions & 0 deletions src/optimizer/esbuild/builder.ts
@@ -0,0 +1,162 @@
import type { Diagnostic, OutputFile, OutputPlatform } from '../types';
import type { EsbuildResult } from './types';
import type { BuildOptions, BuildResult, OutputFile as ESOutputFile, Message } from 'esbuild';
import { createTimer } from '../utils';

/**
* @alpha
*/
export function createEsbuilder(opts: {
outDir: string;
clientOpts?: BuildOptions;
serverOpts?: BuildOptions;
}) {
const results: EsBuildPluginData = {};

const builder = {
build: async () => {
const buildTime = createTimer();

const buildResult: EsbuildResult = {
outputFiles: [],
diagnostics: [],
timers: {
clientBuild: 0,
serverBuild: 0,
totalBuild: 0,
},
};

try {
if (opts.clientOpts) {
opts.clientOpts.outdir = opts.outDir;
const clientTime = createTimer();
results.client = await runEsBuild(opts.clientOpts, results.client);
convertOutFile(
opts.outDir,
buildResult.outputFiles,
'client',
results.client.outputFiles
);
convertMessages(buildResult, results.client, 'client');
buildResult.timers.clientBuild = clientTime();
}

if (opts.serverOpts) {
opts.serverOpts.outdir = opts.outDir;
const serverTime = createTimer();
results.server = await runEsBuild(opts.serverOpts, results.server);
convertOutFile(
opts.outDir,
buildResult.outputFiles,
'server',
results.server.outputFiles
);
convertMessages(buildResult, results.server, 'server');
buildResult.timers.serverBuild = serverTime();
}
} catch (e) {
if (Array.isArray(e.errors)) {
for (const err of e.errors as Message[]) {
buildResult.diagnostics.push({
type: 'error',
message: err.text,
location: err.location,
});
}
} else {
buildResult.diagnostics.push({ type: 'error', message: String(e) });
}
}

if (buildResult.diagnostics.length > 0) {
buildResult.diagnosticsSummary = diagnosticsSummary(buildResult.diagnostics);
}

buildResult.timers.totalBuild = buildTime();
return buildResult;
},
dispose: () => {
if (results.client) {
results.client.rebuild?.dispose();
results.client = undefined;
}
if (results.server) {
results.server.rebuild?.dispose();
results.server = undefined;
}
},
};

return builder;
}

async function runEsBuild(buildOpts: BuildOptions, buildResults: BuildResult | undefined) {
if (buildResults?.rebuild) {
return buildResults.rebuild();
}
const esbuild = await import('esbuild');
return esbuild.build(buildOpts);
}

function convertOutFile(
rootDir: string,
outFiles: OutputFile[],
platform: OutputPlatform,
esbuildFiles?: ESOutputFile[]
) {
if (Array.isArray(esbuildFiles)) {
for (const esbuildFile of esbuildFiles) {
const out: OutputFile = {
path: esbuildFile.path.replace(rootDir, ''),
text: esbuildFile.text,
platform,
};
if (out.path.startsWith('/') || out.path.startsWith('\\')) {
out.path = out.path.substring(1);
}
outFiles.push(out);
}
}
return [];
}

function convertMessages(
esbuildResult: EsbuildResult,
result: BuildResult,
platform: OutputPlatform
) {
for (const err of result.errors) {
esbuildResult.diagnostics.push({
type: 'error',
message: err.text,
location: err.location,
platform,
});
}
for (const warn of result.warnings) {
esbuildResult.diagnostics.push({
type: 'warn',
message: warn.text,
location: warn.location,
platform,
});
}
}

function diagnosticsSummary(diagnostics: Diagnostic[]) {
return diagnostics
.map((d) => {
let m = d.message;
if (d.location) {
m += `\nFile: ${d.location.file}\n${d.location.lineText}`;
}
return m;
})
.join('\n\n');
}

interface EsBuildPluginData {
client?: BuildResult;
server?: BuildResult;
}
2 changes: 2 additions & 0 deletions src/optimizer/esbuild/index.ts
@@ -0,0 +1,2 @@
export { createEsbuilder } from './builder';
export { createClientEsbuildOptions, createServerEsbuildOptions } from './options';
53 changes: 53 additions & 0 deletions src/optimizer/esbuild/options.ts
@@ -0,0 +1,53 @@
import type { Optimizer } from '../types';
import type { BuildOptions } from 'esbuild';
import { clientEsbuildPlugin, serverEsbuildPlugin } from './plugins';

/**
* @alpha
*/
export async function createClientEsbuildOptions(optimizer: Optimizer): Promise<any> {
await optimizer.getTsconfig();

const clientBuildOpts: BuildOptions = {
entryPoints: optimizer.getEntryInputs({ platform: 'client' }),
outdir: optimizer.getRootDir(),
plugins: [clientEsbuildPlugin(optimizer)],
format: 'esm',
bundle: true,
splitting: true,
incremental: true,
write: false,
};

if (optimizer.isDev()) {
clientBuildOpts.sourcemap = 'inline';
} else {
clientBuildOpts.sourcemap = 'external';
clientBuildOpts.minify = true;
clientBuildOpts.define = {
qDev: false as any,
};
}

return clientBuildOpts;
}

/**
* @alpha
*/
export async function createServerEsbuildOptions(optimizer: Optimizer): Promise<any> {
await optimizer.getTsconfig();

const serverBuildOpts: BuildOptions = {
entryPoints: optimizer.getEntryInputs({ platform: 'server' }),
outdir: optimizer.getRootDir(),
plugins: [serverEsbuildPlugin(optimizer)],
format: 'cjs',
platform: 'node',
incremental: true,
write: false,
sourcemap: 'external',
};

return serverBuildOpts;
}

0 comments on commit d07ff46

Please sign in to comment.