@oazmi/build-tools
Version:
general deno build tool scripts which I practically use in all of my typescript repos
125 lines (124 loc) • 7.04 kB
JavaScript
/** the {@link buildNpm} function in this module provides way for you to transform your deno-project to a node-project, using [`dnt`](https://jsr.io/@deno/dnt) under the hood. <br>
* this tool reads your "deno.json" file to figure out most of what needs to be transformed, and comes with a handful of useful preset configurations. <br>
* take a look at {@link BuildNpmConfig} to see what configuration options are available. <br>
* moreover, to use this transformer via cli, use the [`./cli/npm.ts`](./cli/npm.ts) script file (or [`jsr:@oazmi/build-tools/cli/npm`](https://jsr.io/@oazmi/build-tools) if using jsr), and take a look at its {@link CliArgs} for list of supported cli args.
*
* @module
*/
// TODO: allow for user-customization of `entryPoints`, using an approach similar to `/src/dist.ts`.
import * as dntShim from "./_dnt.shims.js";
import { build as dntBuild } from "./deps/jsr.io/@deno/dnt/0.42.1/mod.js";
import { emptyDir, object_entries, pathResolve } from "./deps.js";
import { copyAndCreateFiles, createPackageJson, createTsConfigJson, getDenoJson } from "./funcdefs.js";
import { logBasic, logVerbose, setLog } from "./logger.js";
/** the default configuration used by the {@link buildNpm} function, for missing/unprovided configuration fields. */
export const defaultBuildNpmConfig = {
dir: "./npm/",
deno: "./deno.json",
copy: [
["./assets/", "./assets/"],
["./readme.md", "./readme.md"],
["./license.md", "./license.md"],
["./.github/code_of_conduct.md", "./code_of_conduct.md"],
],
text: [
["./.gitignore", "/node_modules/\n"],
[".npmignore", `
code_of_conduct.md
dist/
docs/
docs_config/
test/
tsconfig.json
typedoc.json
`, { append: true }],
],
};
/** this function transforms your deno-project to a node-project, using [`dnt`](https://jsr.io/@deno/dnt) under the hood.
* this function reads your "deno.json" file to figure out most of what needs to be transformed, and comes with a handful of useful preset configurations. <br>
* take a look at {@link BuildNpmConfig} to see what configuration options are available. <br>
* moreover, to use this transformer via cli, use the [`./cli/npm.ts`](./cli/npm.ts) script file (or [`jsr:@oazmi/build-tools/cli/npm`](https://jsr.io/@oazmi/build-tools) if using jsr), and take a look at its {@link CliArgs} for list of supported cli args.
*/
export const buildNpm = async (build_config = {}) => {
setLog(build_config);
const { dir, deno, copy = [], text = [], dnt, dryrun = false } = { ...defaultBuildNpmConfig, ...build_config }, abs_dir = pathResolve(dir), abs_deno = pathResolve(deno);
const { name: library_name = "library", exports, } = await getDenoJson(deno);
const mainEntrypoint = typeof exports === "string" ? exports : exports["."];
logVerbose("the main entry-point of your npm-build will be:", mainEntrypoint);
logVerbose("current npm-build configuration is:", { dir, deno, copy, text, dnt, dryrun });
logVerbose("[in-memory] creating a \"package.json\" file from your \"deno.json\" file");
const package_json = await createPackageJson(deno, {
sideEffects: false,
scripts: {
"build-dist": `npm run build-esm && npm run build-esm-minify && npm run build-iife && npm run build-iife-minify`,
"build-esm": `npx esbuild "${mainEntrypoint}" --bundle --format=esm --outfile="./dist/${library_name}.esm.js"`,
"build-esm-minify": `npx esbuild "${mainEntrypoint}" --bundle --minify --format=esm --outfile="./dist/${library_name}.esm.min.js"`,
"build-iife": `npx esbuild "${mainEntrypoint}" --bundle --format=iife --outfile="./dist/${library_name}.iife.js"`,
"build-iife-minify": `npx esbuild "${mainEntrypoint}" --bundle --minify --format=iife --outfile="./dist/${library_name}.iife.min.js"`,
}
});
// we must delete the `exports` property, as it will override the correct version generated by `dntBuild`.
delete package_json["exports"];
logVerbose("[in-memory] creating a \"tsconfig.json\" file from your \"deno.json\" file");
const tsconfig_json = await createTsConfigJson(deno);
logBasic("[in-memory] generated \"package.json\" and \"tsconfig.json\" files.");
logVerbose("[in-fs] emptying your npm-build directory:", abs_dir);
if (!dryrun) {
await emptyDir(dir);
}
logBasic("[in-fs] transforming your deno project to an npm-build via \`dnt\`");
if (!dryrun) {
await dntBuild({
entryPoints: object_entries(exports).map(([export_path, source_path]) => ({
name: export_path,
path: source_path,
})),
outDir: dir,
shims: { deno: "dev" },
package: package_json,
compilerOptions: { ...tsconfig_json.compilerOptions, target: "Latest" },
typeCheck: false,
declaration: "inline",
esModule: true,
scriptModule: false,
test: false,
skipNpmInstall: true,
// override the test pattern, so that no tests are included, and no Deno.test shims are created for the entirety of the transpiled package.
// see the details here: "https://github.com/denoland/dnt?tab=readme-ov-file#test-file-matching"
testPattern: "TEST_NOTHING",
// TODO: there's no need for mapping, as jsr imports are converted into npm-compatible packages on the fly.
// however, I loose the ability to map it from my package's npm releases as a consequence.
// consider whether or not I'd like to have my dependencies as jsr imports or npm imports.
// mappings: Object.fromEntries(
// ["alias", "binder", "browser", "eightpack", "lambda", "pathman", "timeman", "struct", "typedefs",].map((submodule_path) => {
// return [
// "jsr:@oazmi/kitchensink@0.9.1/" + submodule_path,
// {
// name: "@oazmi/kitchensink",
// version: "0.9.1",
// subPath: submodule_path,
// }
// ]
// })
// ),
...dnt,
});
}
// first we add our `tsconfig.json` config to the list of text files to write.
// we don't push it into `text`, because it will potentially mutate the `text` property in the `defaultBuildNpmConfig` variable.
const tsconfig_text_creation = ["./tsconfig.json", JSON.stringify(tsconfig_json)];
// creating new text files and copying over files to the destination `dir` folder.
await copyAndCreateFiles({ dir, deno, copy, text: [...text, tsconfig_text_creation], dryrun });
return {
dir: abs_dir,
files: [],
cleanup: async () => {
logBasic("[in-fs] deleting your npm-build directory:", abs_dir);
if (dryrun) {
return;
}
await emptyDir(abs_dir);
await dntShim.Deno.remove(abs_dir);
}
};
};