turbo-gulp
Version:
Gulp tasks to boost high-quality projects.
270 lines (269 loc) • 11.8 kB
JavaScript
/**
* This module defines the _lib_ target type used to create libraries for other projects.
*
* In the following list of tasks, `{target}` represents the name of the target as defined by the `name` property
* of the target options.
* The _lib_ target provides the following tasks:
*
* ## {target}:build
*
* Performs a full build of the library to the build directory, used for development.
* This copies the static assets and compiles the scripts.
*
* The following sub-tasks are available:
* - `{target}:build:copy`: Only copy the static assets
* - `{target}:build:script`: Only compile the scripts
*
* For distribution builds, use `{target:dist}`
*
* ## {target}:watch
*
* Watch the files and run incremental builds on change.
* This useful during development to get build errors reported immediately or accelerate the code/test cycle.
* You can combine it with _Nodemon_ to continuously restart your Node process when changing the source.
*
* ## {target}:dist
*
* Performs a full build of the library to the dist directory, used for distribution (ie. publication to _npm_).
* This build creates a fully autonomous directory with its own `package.json`, source code, license file, etc.
* This allows to use a different structure for distribution rather than structure of the repo, the main benefit is
* to provide support for deep package imports (`import * as mod from "my-lib/deep/module"`) by placing the build
* at the root of the package.
* This build also allows you to remap the `package.json`, for example to set the version dynamically.
*
* The following sub-tasks are available:
* - `{target}:dist:publish`: Publish the package to an _npm_ registry (it honors the `registry` option, to publish
* to private _npm_ registries such as _Verdaccio_). It uses the authentication token of the current user, this
* token is in `~/.npmrc`. For CI, you can use the following command to set the token the registry `npm.example.com`.
* (for the official registry, use `//registry.npmjs.org`):
* ```
* echo "//npm.example.com/:_authToken=\"${NPM_TOKEN}\"" > ~/.npmrc
* ```
* - `{target}:dist:copy-src`: Only copy the source files to the build directory.
* - `{target}:dist:package.json`: Copy (and eventually transform) the root `package.json` to the build directory.
*
* For development builds, use `{target:build}`.
*
* ## {target}:typedoc
*
* Generate _Typedoc_ documentation.
*
* ## {target}:typedoc:deploy
*
* Deploy the _Typedoc_ documentation using _git_. This can be used to easily deploy the documentation to the
* `gh-pages` branch.
*
* ## {target}:clean
*
* Remove both the build and dist directories corresponding to this target.
*
* ## {target}:tsconfig.json
*
* Emit a `tsconfig.json` file corresponding to the configuration for this target. This allows to compile it using
* the command line `tsc` program. This is also useful for IDE to auto-detect the configuration of the project.
*
* @module targets/lib
*/
import { Minimatch } from "minimatch";
import path from "path";
import { getBuildTypescriptTask } from "../target-tasks/build-typescript";
import { getTypedocTask } from "../target-tasks/typedoc";
import { branchPublish } from "../utils/branch-publish";
import { getHeadHash } from "../utils/git";
import * as matcher from "../utils/matcher";
import { npmPublish } from "../utils/npm-publish";
import { readJsonFile } from "../utils/project";
import { generateBaseTasks, getCopy, gulpBufferSrc, nameTask, resolveTargetBase, } from "./_base";
/**
* Resolve absolute paths and dependencies for the provided target.
*
* @param target Non-resolved target.
* @return Resolved target.
*/
function resolveLibTarget(target) {
const base = resolveTargetBase(target);
let typedoc = undefined;
if (target.typedoc !== undefined) {
typedoc = {
dir: path.posix.join(base.project.absRoot, target.typedoc.dir),
name: target.typedoc.name,
deploy: target.typedoc.deploy,
};
}
let dist;
if (target.dist === undefined || target.dist === false) {
dist = false;
}
else {
const defaultDistDir = path.posix.join(base.project.absDistDir, target.name);
const defaultPackageJsonMap = pkg => pkg;
const defaultCopy = (dest) => [{
files: ["./*.md"],
}];
if (target.dist === true) {
dist = {
distDir: defaultDistDir,
packageJsonMap: defaultPackageJsonMap,
npmPublish: {},
copySrc: true,
copy: defaultCopy(defaultDistDir),
};
}
else {
const distDir = target.dist.distDir !== undefined ? target.dist.distDir : defaultDistDir;
dist = {
distDir,
packageJsonMap: target.dist.packageJsonMap !== undefined ? target.dist.packageJsonMap : defaultPackageJsonMap,
npmPublish: target.dist.npmPublish,
copySrc: target.dist.copySrc !== undefined ? target.dist.copySrc : true,
copy: defaultCopy(distDir),
};
}
}
return Object.assign({}, base, { mainModule: target.mainModule, typedoc, dist });
}
/**
* Generates gulp tasks for the provided lib target.
*
* @param gulp Gulp instance used to generate tasks manipulating files.
* @param targetOptions Target configuration.
*/
export function generateLibTasks(gulp, targetOptions) {
const target = resolveLibTarget(targetOptions);
const result = generateBaseTasks(gulp, targetOptions);
const tsOptions = {
tscOptions: target.tscOptions,
tsconfigJson: target.tsconfigJson,
customTypingsDir: target.customTypingsDir,
packageJson: target.project.absPackageJson,
buildDir: target.buildDir,
srcDir: target.srcDir,
scripts: target.scripts,
outModules: target.outModules,
};
// typedoc
if (target.typedoc !== undefined) {
const typedocOptions = target.typedoc;
result.typedoc = nameTask(`${target.name}:typedoc`, gulp.series([result.tsconfigJson, getTypedocTask(gulp, tsOptions, typedocOptions)]));
// typedoc:deploy
if (typedocOptions.deploy !== undefined) {
const deploy = typedocOptions.deploy;
async function deployTypedocTask() {
const commitMessage = `Deploy documentation for ${await getHeadHash()}`;
return branchPublish(Object.assign({}, deploy, { dir: typedocOptions.dir, commitMessage }));
}
result.typedocDeploy = nameTask(`${target.name}:typedoc:deploy`, gulp.series(result.typedoc, deployTypedocTask));
}
}
// dist
if (target.dist !== false) {
const dist = target.dist;
const distTasks = [];
const copyTasks = [];
// Locations for compilation: default to the original sources but compile the copied files if copySrc is used
let srcDir = target.srcDir;
let customTypingsDir = target.customTypingsDir;
// dist:copy:scripts
if (target.dist.copySrc) {
srcDir = path.posix.join(dist.distDir, "_src");
copyTasks.push(nameTask(`${target.name}:dist:copy:scripts`, () => {
return gulp
.src([...target.scripts], { base: target.srcDir })
.pipe(gulp.dest(srcDir));
}));
// dist:copy:custom-typings
if (target.customTypingsDir !== null) {
const srcCustomTypingsDir = target.customTypingsDir;
const destCustomTypingsDir = path.posix.join(dist.distDir, "_custom-typings");
customTypingsDir = destCustomTypingsDir;
copyTasks.push(nameTask(`${target.name}:dist:copy:custom-typings`, () => {
return gulp
.src([path.posix.join(srcCustomTypingsDir, "**/*.d.ts")], { base: srcCustomTypingsDir })
.pipe(gulp.dest(destCustomTypingsDir));
}));
}
// dist:copy:dist
if (target.dist.copy !== undefined) {
const [copyBaseTask, copyBaseWatchTask] = getCopy(gulp, target.project.absRoot, target.dist.distDir, target.dist.copy);
copyTasks.push(nameTask(`${target.name}:dist:copy:dist`, copyBaseTask));
}
}
// dist:copy:lib
if (target.copy !== undefined) {
const [copyBaseTask, copyBaseWatchTask] = getCopy(gulp, target.srcDir, target.dist.distDir, target.copy);
copyTasks.push(nameTask(`${target.name}:dist:copy:lib`, copyBaseTask));
}
result.distCopy = nameTask(`${target.name}:dist:copy`, gulp.parallel(copyTasks));
// Resolve tsconfig for `dist`
const tsconfigJson = target.tsconfigJson !== null ?
path.posix.join(srcDir, "tsconfig.json") :
null;
let scripts = [];
if (srcDir !== target.srcDir) {
for (const script of target.scripts) {
scripts.push(matcher.asString(matcher.join(srcDir, matcher.relative(target.srcDir, new Minimatch(script)))));
}
}
else {
scripts = [...target.scripts];
}
const tsOptions = {
tscOptions: target.tscOptions,
tsconfigJson,
customTypingsDir,
packageJson: target.project.absPackageJson,
buildDir: dist.distDir,
srcDir,
scripts,
outModules: target.outModules,
};
// dist:scripts
distTasks.push(nameTask(`${target.name}:dist:scripts`, gulp.series(result.distCopy, getBuildTypescriptTask(gulp, tsOptions))));
// dist:package.json
{
async function distPackageJsonTask() {
let pkg = await readJsonFile(target.project.absPackageJson);
if (typeof target.mainModule === "string") {
pkg.main = target.mainModule;
pkg.types = `${target.mainModule}.d.ts`;
}
pkg.gitHead = await getHeadHash();
pkg = dist.packageJsonMap(pkg);
return gulpBufferSrc("package.json", Buffer.from(JSON.stringify(pkg, null, 2)))
.pipe(gulp.dest(dist.distDir));
}
result.distPackageJson = nameTask(`${target.name}:dist:package.json`, distPackageJsonTask);
distTasks.push(result.distPackageJson);
}
const distTask = result.clean !== undefined ?
gulp.series(result.clean, gulp.parallel(distTasks)) :
gulp.parallel(distTasks);
result.dist = nameTask(`${target.name}:dist`, distTask);
if (dist.npmPublish !== undefined) {
const npmPublishOptions = dist.npmPublish;
const npmPublishTask = async () => {
return npmPublish(Object.assign({}, npmPublishOptions, { directory: dist.distDir }));
};
npmPublishTask.displayName = `${target.name}:dist:publish`;
gulp.task(npmPublishTask);
result.distPublish = nameTask(`${target.name}:dist:publish`, gulp.series(distTask, npmPublishTask));
}
}
return result;
}
/**
* Generates and registers gulp tasks for the provided lib target.
*
* @param gulp Gulp instance where the tasks will be registered.
* @param targetOptions Target configuration.
*/
export function registerLibTasks(gulp, targetOptions) {
const tasks = generateLibTasks(gulp, targetOptions);
for (const key in tasks) {
const task = tasks[key];
if (task !== undefined) {
gulp.task(task);
}
}
return tasks;
}