projenrc/bundle.ts (39 lines of code) (raw):
import * as pj from 'projen';
/**
* Bundling properties.
*/
export interface BundleProps {
/**
* List of entry-points to bundle.
*
* @default - the 'main' file as specified in package.json.
*/
readonly entryPoints?: string[];
/**
* Path to attributions file that will be created / validated.
* This path is relative to the package directory.
*
* @default 'THIRD_PARTY_LICENSES'
*/
readonly attributionsFile?: string;
/**
* External packages that cannot be bundled.
*
* @default - no external references.
*/
readonly externals?: Externals;
/**
* External resources that need to be embedded in the bundle.
*
* These will be copied over to the appropriate paths before packaging.
*/
readonly resources?: {[src: string]: string};
/**
* A list of licenses that are allowed for bundling.
* If any dependency contains a license not in this list, bundling will fail.
*
* @default - Default list
*/
readonly allowedLicenses?: string[];
/**
* Packages matching this regular expression will be excluded from attribution.
*/
readonly dontAttribute?: string;
/**
* Basic sanity check to run against the created bundle.
*
* @default - no check.
*/
readonly test?: string;
/**
* Include a sourcemap in the bundle.
*
* @default "inline"
*/
readonly sourcemap?: 'linked' | 'inline' | 'external' | 'both';
/**
* Minifies the bundled code.
*
* @default false
*/
readonly minify?: boolean;
/**
* Removes whitespace from the code.
* This is enabled by default when `minify` is used.
*
* @default false
*/
readonly minifyWhitespace?: boolean;
/**
* Renames local variables to be shorter.
* This is enabled by default when `minify` is used.
*
* @default false
*/
readonly minifyIdentifiers?: boolean;
/**
* Rewrites syntax to a more compact format.
* This is enabled by default when `minify` is used.
*
* @default false
*/
readonly minifySyntax?: boolean;
}
/**
* External packages that cannot be bundled.
*/
export interface Externals {
/**
* External packages that should be listed in the `dependencies` section
* of the manifest.
*/
readonly dependencies?: readonly string[];
/**
* External packages that should be listed in the `optionalDependencies` section
* of the manifest.
*/
readonly optionalDependencies?: readonly string[];
}
export class BundleCli extends pj.Component {
constructor(project: pj.Project, options: BundleProps) {
super(project);
const args = [
...(options.externals?.dependencies ?? []).map(d => `--external ${d}:runtime`),
...(options.externals?.optionalDependencies ?? []).map(d => `--external ${d}:optional`),
...(options.allowedLicenses ?? []).map(l => `--allowed-license "${l}"`),
...options.dontAttribute ? [`--dont-attribute ${quoteShellArg(options.dontAttribute)}`] : [],
...options.test ? [`--test ${quoteShellArg(options.test)}`] : [],
...(options.entryPoints ?? []).map(e => `--entrypoint ${quoteShellArg(e)}`),
// All of these options are not available via the CLI api
/*
...options.sourcemap ? [`--sourcemap ${JSON.stringify(options.sourcemap)}`] : [],
...options.minify ? ['--minify'] : [],
...options.minifyWhitespace ? ['--minify-whitespace'] : [],
...options.minifyIdentifiers ? ['--minify-identifiers'] : [],
...options.minifySyntax ? ['--minify-syntax'] : [],
...Object.entries(options.resources ?? {}).map(([src, dst]) => `--resource ${JSON.stringify(src)}:${JSON.stringify(dst)}`),
*/
];
// Generate the license file
project.postCompileTask.exec(['node-bundle', 'validate', '--fix', ...args].join(' '));
// `node-bundle` replaces `npm pack`
project.packageTask.reset();
project.packageTask.exec('mkdir -p dist/js');
project.packageTask.exec(['node-bundle', 'pack', '--destination', 'dist/js', ...args].join(' '));
}
}
/**
* Quote a shell argument (for POSIX shells)
*
* Uses single quotes (no character means anything special other than
* single quotes themselvs), and escape single quotes by exiting the string,
* adding in a literal single quote, and re-entering the string.
*
* as'df
*
* Gets rendered as
*
* 'as'\''df'
*/
function quoteShellArg(x: string) {
return `'${x.replace(/'/g, "'\\''")}'`;
}