Skip to content

Commit

Permalink
new useTsconfigPaths & add retry behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
PabloSzx committed Nov 6, 2021
1 parent afd2edb commit b8a13ba
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 96 deletions.
7 changes: 7 additions & 0 deletions .changeset/smooth-guests-poke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'bob-esbuild': patch
---

New "useTsconfigPaths" global config that resolves root tsconfig "paths"

Closes #156
1 change: 1 addition & 0 deletions examples/basic/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"emitDeclarationOnly": false,
"noEmit": true,
"resolveJsonModule": true
}
Expand Down
1 change: 1 addition & 0 deletions packages/bob/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"rollup": "^2.59.0",
"rollup-plugin-delete": "^2.0.0",
"rollup-plugin-node-externals": "^2.2.0",
"rollup-plugin-tsconfig-paths": "^1.0.15",
"tree-kill": "^1.2.2",
"tsconfck": "^1.1.1"
},
Expand Down
5 changes: 5 additions & 0 deletions packages/bob/src/config/cosmiconfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ export interface BobConfig extends Pick<ConfigOptions, 'clean' | 'inputFiles' |
* Set configurations for specific packages
*/
packageConfigs?: Record<string, Omit<ConfigOptions, 'cwd'>>;

/**
* @default false
*/
useTsconfigPaths?: boolean;
}

export type ResolvedBobConfig = PickRequired<BobConfig, 'rootDir' | 'clean' | 'distDir'>;
Expand Down
39 changes: 27 additions & 12 deletions packages/bob/src/config/rollup.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { bobEsbuildPlugin } from 'bob-esbuild-plugin';
import path from 'path';
import path, { join } from 'path';
import type { InputOptions, OutputOptions, Plugin, RollupBuild } from 'rollup';
import del from 'rollup-plugin-delete';
import externals from 'rollup-plugin-node-externals';
Expand All @@ -10,6 +10,7 @@ import { globalConfig } from './cosmiconfig';
import { GetPackageBuildConfig } from './packageBuildConfig';
import { generatePackageJson } from './packageJson';
import { rollupBin } from './rollupBin';
import { retry } from '../utils/retry';

export interface ConfigOptions {
/**
Expand Down Expand Up @@ -68,21 +69,26 @@ export async function getRollupConfig(optionsArg: ConfigOptions = {}) {

const distDir = globalOptions.distDir;

const globbyPkg = await import('globby');
const [globbyPkg, tsPaths] = await Promise.all([
import('globby'),
globalOptions.useTsconfigPaths ? import('rollup-plugin-tsconfig-paths').then(v => v.tsconfigPaths) : null,
]);

const globby = globbyPkg.default || (globbyPkg as any).globby;

const input = (
await Promise.all(
inputFiles.map(pattern => {
const glob = path.join(cwd, pattern).replace(/\\/g, '/');
debug('Checking glob pattern: ' + glob);
return globby(glob);
})
const input = await retry(async () =>
(
await Promise.all(
inputFiles.map(pattern => {
const glob = path.join(cwd, pattern).replace(/\\/g, '/');
debug('Checking glob pattern: ' + glob);
return globby(glob);
})
)
)
)
.flat()
.filter((file, index, self) => self.indexOf(file) === index);
.flat()
.filter((file, index, self) => self.indexOf(file) === index)
);

if (!input.length) throw Error('No input files found!');

Expand Down Expand Up @@ -219,6 +225,15 @@ export async function getRollupConfig(optionsArg: ConfigOptions = {}) {
})
);
}

if (tsPaths) {
plugins.push(
tsPaths({
tsConfigPath: join(globalOptions.rootDir, 'tsconfig.json'),
})
);
}

const inputOptions: InputOptions = {
input,
plugins,
Expand Down
5 changes: 3 additions & 2 deletions packages/bob/src/config/tsconfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { join } from 'path';
import { parse } from 'tsconfck';
import { error } from '../log/error';
import { globalConfig } from './cosmiconfig';
import { retry } from '../utils/retry';

export const resolvedTsconfig = (async () => {
export const resolvedTsconfig = retry(async () => {
const {
config: { rootDir: configRootDir, singleBuild },
} = await globalConfig;
Expand All @@ -26,7 +27,7 @@ export const resolvedTsconfig = (async () => {
return {
outDir,
};
})().catch(err => {
}).catch(err => {
error(err);
process.exit(1);
});
103 changes: 55 additions & 48 deletions packages/bob/src/tsc/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { globalConfig } from '../config/cosmiconfig';
import { debug } from '../log/debug';
import { error } from '../log/error';
import { getHash } from './hash';
import { retry } from '../utils/retry';

const { copy, pathExists } = fsExtra;

Expand All @@ -21,64 +22,70 @@ export async function buildTsc(options: TSCOptions = {}) {

const startTime = Date.now();

const hashPromise = getHash();

const tscCommand = options.tscBuildCommand || globalTsc.tscBuildCommand || 'tsc --emitDeclarationOnly';

const { default: globby } = await import('globby');

const targetDirs = await globby(dirs, {
expandDirectories: false,
absolute: false,
onlyDirectories: true,
cwd: rootDirCwd,
});
await retry(async () => {
const hashPromise = Promise.allSettled([getHash()]).then(v => v[0]);

const { shouldBuild, cleanHash } = await hashPromise;
const tscCommand = options.tscBuildCommand || globalTsc.tscBuildCommand || 'tsc --emitDeclarationOnly';

if (shouldBuild) {
debug(!targetDirs.length ? 'No target directories for built types!' : 'Building types for: ' + targetDirs.join(' | '));

const tsconfig = globalTsc.tsconfig;
await command(tscCommand + (tsconfig ? ` -p ${tsconfig}` : ''), {
const targetDirs = await globby(dirs, {
expandDirectories: false,
absolute: false,
onlyDirectories: true,
cwd: rootDirCwd,
stdio: 'inherit',
}).catch(err => {
cleanHash();

throw err;
});
}

const { outDir } = await resolvedTsconfig;
const { shouldBuild, cleanHash } = await hashPromise.then(v => {
if (v.status === 'rejected') throw v.reason;

await Promise.all(
targetDirs.map(async dir => {
const from = resolve(rootDirCwd, `${outDir}/${dir}/src`);

if (!(await pathExists(from))) return;
return v.value;
});

await copy(from, resolve(rootDirCwd, `${dir}/${distDir}`), {
filter(src) {
// Check if is directory
if (!parse(src).ext) return true;
if (shouldBuild) {
debug(!targetDirs.length ? 'No target directories for built types!' : 'Building types for: ' + targetDirs.join(' | '));

return src.endsWith('.d.ts');
},
const tsconfig = globalTsc.tsconfig;
await command(tscCommand + (tsconfig ? ` -p ${tsconfig}` : ''), {
cwd: rootDirCwd,
stdio: 'inherit',
}).catch(err => {
const errCode: string | undefined = err?.code;
// Silence these specific error that happen when multiple processes access the same file concurrently
switch (errCode) {
case 'ENOENT':
case 'EBUSY':
case 'EPERM':
return;
}

error(err);
});
})
);
cleanHash();

debug(`Types ${shouldBuild ? 'built' : 'prepared'} in ${Date.now() - startTime}ms`);
throw err;
});
}

const { outDir } = await resolvedTsconfig;

await Promise.all(
targetDirs.map(async dir => {
const from = resolve(rootDirCwd, `${outDir}/${dir}/src`);

if (!(await pathExists(from))) return;

await copy(from, resolve(rootDirCwd, `${dir}/${distDir}`), {
filter(src) {
// Check if is directory
if (!parse(src).ext) return true;

return src.endsWith('.d.ts');
},
}).catch(err => {
const errCode: string | undefined = err?.code;
// Silence these specific error that happen when multiple processes access the same file concurrently
switch (errCode) {
case 'ENOENT':
case 'EBUSY':
case 'EPERM':
return;
}

error(err);
});
})
);

debug(`Types ${shouldBuild ? 'built' : 'prepared'} in ${Date.now() - startTime}ms`);
});
}
70 changes: 36 additions & 34 deletions packages/bob/src/tsc/hash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { hashElement } from 'folder-hash';
import { existsSync, unlinkSync } from 'fs';
import fsExtra from 'fs-extra';
import { resolve } from 'path';

import { retry } from '../utils/retry';
import { globalConfig } from '../config/cosmiconfig';
import { resolvedTsconfig } from '../config/tsconfig';

Expand All @@ -25,39 +25,41 @@ export async function getHash(): Promise<{

const typesHashJSON = resolve(rootDir, outDir, 'types-hash.json');

const [currentHash, jsonHash] = await Promise.all([
hashElement(rootDir, {
files: {
exclude: hash?.files?.exclude || ['*.d.ts'],
include: hash?.files?.include || ['*.ts', '*.tsx', '*.json'],
},
folders: {
exclude: [
outDir,
distDir,
'node_modules',
'lib',
'temp',
'dist',
'.git',
'.next',
'coverage',
'.vscode',
'.github',
'.changeset',
'.husky',
'.bob',
...(hash?.folders?.exclude || []),
],
},
}),
existsSync(typesHashJSON)
? fsExtra.readJSON(typesHashJSON).then(
v => v as { hash: string },
() => null
)
: null,
]);
const [currentHash, jsonHash] = await retry(async () =>
Promise.all([
hashElement(rootDir, {
files: {
exclude: hash?.files?.exclude || ['*.d.ts'],
include: hash?.files?.include || ['*.ts', '*.tsx', '*.json'],
},
folders: {
exclude: [
outDir,
distDir,
'node_modules',
'lib',
'temp',
'dist',
'.git',
'.next',
'coverage',
'.vscode',
'.github',
'.changeset',
'.husky',
'.bob',
...(hash?.folders?.exclude || []),
],
},
}),
existsSync(typesHashJSON)
? fsExtra.readJSON(typesHashJSON).then(
v => v as { hash: string },
() => null
)
: null,
])
);

const cleanHash = () => {
try {
Expand Down
19 changes: 19 additions & 0 deletions packages/bob/src/utils/retry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export async function retry<T>(cb: () => Promise<T>, times: number = 3) {
for (let i = 0; i < times - 1; ++i) {
try {
const value = await cb();

return value;
} catch (err) {}
}

try {
const value = await cb();

return value;
} catch (err) {
err instanceof Error && Error.captureStackTrace(err, retry);

throw err;
}
}
10 changes: 10 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b8a13ba

Please sign in to comment.