Skip to content

Commit

Permalink
chore: add comments to build scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
adamdbradley committed Jul 17, 2021
1 parent 9821cc4 commit 0f1e36e
Show file tree
Hide file tree
Showing 13 changed files with 207 additions and 57 deletions.
16 changes: 14 additions & 2 deletions scripts/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { readFileSync, writeFileSync } from 'fs';
import { join } from 'path';
import { loadConfig } from './util';

export function apiExtractor() {
/**
* Create each submodule's bundled dts file, and ensure
* the public API has not changed for a production build.
*/
function apiExtractor() {
const config = loadConfig(process.argv.slice(2));

function createTypesApi(submodule: string, corePath?: string) {
Expand All @@ -21,24 +25,32 @@ export function apiExtractor() {
fixDtsContent(dtsPath, dtsPath, corePath);
}

// Run the api extractor for each of the submodules
createTypesApi('core');
createTypesApi('optimizer');
createTypesApi('server', '../core');
createTypesApi('testing', '../core');

// the jsx-runtime.d.ts file was already generated with tsc, use this one
const jsxRuntimeSrcPath = join(config.tscDir, 'src', 'jsx_runtime.d.ts');
const jsxRuntimeDestPath = join(config.pkgDir, 'jsx-runtime.d.ts');
fixDtsContent(jsxRuntimeSrcPath, jsxRuntimeDestPath, './core');

console.log('🦖', 'api generator');
console.log('🦖', 'submodule APIs generated');
}

/**
* Fix up the generated dts content, and ensure it's using a relative
* path to find the core.d.ts file, rather than node resolving it.
*/
function fixDtsContent(srcPath: string, destPath: string, corePath?: string) {
let dts = readFileSync(srcPath, 'utf-8');
if (corePath) {
dts = dts.replace(/@builder\.io\/qwik/g, corePath);
}
// for some reason api-extractor is adding this in ¯\_(ツ)_/¯
dts = dts.replace('{};', '');

writeFileSync(destPath, dts);
}

Expand Down
8 changes: 8 additions & 0 deletions scripts/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ import { submoduleTesting } from './submodule-testing';
import { mkdirSync, rmSync } from 'fs';
import type { BuildConfig } from './util';

/**
* Complete a full build for all of the package's submodules. Passed in
* config has all the correct absolute paths to read from and write to.
* Additionally, a dev build does not empty the directory, and uses
* esbuild for each of the submodules for speed. A production build will
* use TSC + Rollup + Terser for the core submodule.
*/
export async function build(config: BuildConfig) {
try {
if (!config.dev) {
Expand All @@ -34,5 +41,6 @@ export async function build(config: BuildConfig) {
await submoduleOptimizer(config);
} catch (e) {
console.error(e);
process.exit(1);
}
}
4 changes: 4 additions & 0 deletions scripts/copy-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import type { BuildConfig } from './util';
import { copyFile } from 'fs/promises';
import { basename, join } from 'path';

/**
* Manually copy some root files, such as README.md and LICENSE
* to the published package directory.
*/
export async function copyFiles(config: BuildConfig) {
const rootFiles = ['README.md', 'LICENSE'];

Expand Down
3 changes: 3 additions & 0 deletions scripts/devserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { build } from 'esbuild';
import { join } from 'path';
import { BuildConfig, importPath, watcher } from './util';

/**
* Generate the internal integration dev server cjs module.
*/
export async function buildDevServer(config: BuildConfig) {
const integrationDir = join(config.rootDir, 'integration');

Expand Down
15 changes: 14 additions & 1 deletion scripts/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
const { register } = require('esbuild-register/dist/node');
/**
* This is the root build scripts module (keep in commonjs). It's only a .js file
* but will handling registering typescript files with esbuild-register
* to allow NodeJS to build .ts files on-demand.
*/

const { dirname, join } = require('path');
const { register } = require('esbuild-register/dist/node');

// allows NodeJS to compile TypeScript files
register({ target: 'node15' });

const { build } = require('./build.ts');
const { loadConfig } = require('./util.ts');

const args = process.argv.slice(2);

// load our build config, which figures out all the paths
// the rest of the build process uses.
const config = loadConfig(args);

if (process.env.BAZEL_NODE_MODULES_ROOTS) {
// This is a signal that Bazel has started this script
// If Bazel is running this, then find out where it
// would like to see the build output to be written.
config.pkgDir = dirname(join(process.cwd(), args[0]));
config.dev = true;
}

// let's do this!
build(config);
123 changes: 73 additions & 50 deletions scripts/package-json.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import type { BuildConfig } from './util';
import { access, readFile, writeFile } from 'fs/promises';
import type { BuildConfig, PackageJSON } from './util';
import { readFile, writeFile } from 'fs/promises';
import { join } from 'path';

/**
* The published build does not use the package.json found in the root directory.
* This function generates the package.json file for package to be published.
* Note that some of the properties can be pulled from the root package.json.
*/
export async function generatePackageJson(config: BuildConfig) {
const pkgJsonRoot = join(config.rootDir, 'package.json');
const pkgJsonDist = join(config.pkgDir, 'package.json');

const pkg = JSON.parse(await readFile(pkgJsonRoot, 'utf-8'));
const rootPkg: PackageJSON = JSON.parse(await readFile(pkgJsonRoot, 'utf-8'));

const distPkg = {
name: pkg.name,
version: pkg.version,
description: pkg.description,
license: pkg.license,
const distPkg: PackageJSON = {
name: rootPkg.name,
version: rootPkg.version,
description: rootPkg.description,
license: rootPkg.license,
main: './core.cjs',
module: './core.mjs',
types: './core.d.ts',
Expand Down Expand Up @@ -44,12 +49,17 @@ export async function generatePackageJson(config: BuildConfig) {
},
'./package.json': './package.json',
},
contributors: pkg.contributors,
homepage: pkg.homepage,
repository: pkg.repository,
bugs: pkg.bugs,
keywords: pkg.keywords,
engines: pkg.engines,
files: Array.from(new Set(PACKAGE_FILES)).sort((a, b) => {
if (a.toLocaleLowerCase() < b.toLocaleLowerCase()) return -1;
if (a.toLocaleLowerCase() > b.toLocaleLowerCase()) return 1;
return 0;
}),
contributors: rootPkg.contributors,
homepage: rootPkg.homepage,
repository: rootPkg.repository,
bugs: rootPkg.bugs,
keywords: rootPkg.keywords,
engines: rootPkg.engines,
};

const pkgContent = JSON.stringify(distPkg, null, 2);
Expand All @@ -59,39 +69,52 @@ export async function generatePackageJson(config: BuildConfig) {
console.log('👻', 'generate package.json');
}

export async function validatePackageJson(config: BuildConfig) {
const pkgPath = join(config.pkgDir, 'package.json');
const pkg = JSON.parse(await readFile(pkgPath, 'utf-8'));

await Promise.all([
validatePath(config, pkg.main),
validatePath(config, pkg.module),
validatePath(config, pkg.types),
]);

const exportKeys = Object.keys(pkg.exports);

await Promise.all(
exportKeys.map(async (exportKey) => {
const val = pkg.exports[exportKey];
if (typeof val === 'string') {
await validatePath(config, val);
} else {
await validatePath(config, val.import);
await validatePath(config, val.require);
}
})
);
}

async function validatePath(config: BuildConfig, path: string) {
try {
await access(join(config.pkgDir, path));
} catch (e) {
console.error(
`Error validating path "${path}" inside of "${join(config.pkgDir, 'package.json')}"`
);
console.error(e);
process.exit(1);
}
}
/**
* These are the exact outputs that should end up in the published package.
* This is used to create the package.json "files" property.
*/
const PACKAGE_FILES = [
'core.cjs',
'core.cjs.map',
'core.min.mjs',
'core.mjs',
'core.mjs.map',
'core.d.ts',
'jsx-runtime.cjs',
'jsx-runtime.mjs',
'jsx-runtime.d.ts',
'LICENSE',
'optimizer.cjs',
'optimizer.cjs.map',
'optimizer.mjs',
'optimizer.mjs.map',
'optimizer.d.ts',
'package.json',
'qwikloader.js',
'qwikloader.debug.js',
'qwikloader.optimize.js',
'qwikloader.optimize.debug.js',
'README.md',
'server/index.cjs',
'server/index.cjs.map',
'server/index.mjs',
'server/index.mjs.map',
'server/index.d.ts',
'testing/index.cjs',
'testing/index.cjs.map',
'testing/index.mjs',
'testing/index.mjs.map',
'testing/index.d.ts',
'testing/jest-preprocessor.cjs',
'testing/jest-preprocessor.cjs.map',
'testing/jest-preprocessor.mjs',
'testing/jest-preprocessor.mjs.map',
'testing/jest-preset.cjs',
'testing/jest-preset.cjs.map',
'testing/jest-preset.mjs',
'testing/jest-preset.mjs.map',
'testing/jest-setuptestframework.cjs',
'testing/jest-setuptestframework.cjs.map',
'testing/jest-setuptestframework.mjs',
'testing/jest-setuptestframework.mjs.map',
];
7 changes: 7 additions & 0 deletions scripts/submodule-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import { minify } from 'terser';
import { BuildConfig, banner, target, watcher, fileSize } from './util';
import { readFile, writeFile } from 'fs/promises';

/**
* Build the core package which is also the root package: @builder.io/qwik
*
* Uses esbuild during development (cuz it's super fast) and
* TSC + Rollup + Terser for production, because it generates smaller code
* that minifies better.
*/
export function submoduleCore(config: BuildConfig) {
if (config.dev) {
return submoduleCoreDev(config);
Expand Down
13 changes: 12 additions & 1 deletion scripts/submodule-jsx-runtime.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
import { build, BuildOptions } from 'esbuild';
import { join } from 'path';
import { BuildConfig, banner, importPath, target, watcher } from './util';
import { BuildConfig, importPath, target, watcher } from './util';

/**
* Builds @builder.io/qwik/jsx-runtime
*
* This build mainly is re-exports the jsx runtime functions
* provided by the core. Internally, the core's JSX renderer
* is using the latest jsx transform, but Qwik provides both
* the legacy `h()` jsx factory, and the `jsx()` runtime.
*
* - https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html
* - https://www.typescriptlang.org/tsconfig#jsxImportSource
*/
export async function submoduleJsxRuntime(config: BuildConfig) {
const submodule = 'jsx-runtime';

Expand Down
3 changes: 3 additions & 0 deletions scripts/submodule-optimizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { join } from 'path';
import { BuildConfig, banner, nodeBuiltIns, target, watcher } from './util';
import { readFileSync } from 'fs';

/**
* Builds @builder.io/optimizer
*/
export async function submoduleOptimizer(config: BuildConfig) {
const submodule = 'optimizer';

Expand Down
7 changes: 6 additions & 1 deletion scripts/submodule-qwikloader.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { InputOptions, OutputOptions, rollup, Plugin } from 'rollup';
import { minify, MinifyOptions } from 'terser';
import { BuildConfig, fileSize, rollupOnWarn } from './util';
import { statSync } from 'fs';
import { join } from 'path';
import { Optimizer } from '../src/optimizer';

/**
* Builds the qwikloader javascript files. These files can be used
* by other tooling, and are provided in the package so CDNs could
* point to them. The @builder.io/optimizer submodule also provides
* a utility function.
*/
export async function submoduleQwikLoader(config: BuildConfig) {
const optimizer = new Optimizer({
rootDir: config.rootDir,
Expand Down
6 changes: 6 additions & 0 deletions scripts/submodule-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import { build, BuildOptions } from 'esbuild';
import { join } from 'path';
import { BuildConfig, banner, importPath, target, watcher, nodeBuiltIns } from './util';

/**
* Builds @builder.io/server
*
* This is submodule for helping to generate server-side rendered pages,
* along with providing utilities for prerendering and unit testing.
*/
export async function submoduleServer(config: BuildConfig) {
const submodule = 'server';

Expand Down
3 changes: 3 additions & 0 deletions scripts/submodule-testing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import {
injectDirname,
} from './util';

/**
* Builds @builder.io/testing
*/
export async function submoduleTesting(config: BuildConfig) {
const submodule = 'testing';

Expand Down
Loading

0 comments on commit 0f1e36e

Please sign in to comment.