Skip to content
This repository has been archived by the owner on Aug 16, 2022. It is now read-only.

Commit

Permalink
chore(tools): add tsc-prog to build workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
unicornware committed Oct 12, 2021
1 parent 7c38efc commit a14fd44
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 107 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@
"ts-jest": "27.0.5",
"ts-node": "10.2.1",
"ts-patch": "1.4.4",
"tsc-prog": "2.2.1",
"tsconfig": "7.0.0",
"tsconfig-paths": "3.11.0",
"typescript": "4.4.3",
"yargs": "17.2.1"
Expand Down
130 changes: 78 additions & 52 deletions tools/cli/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,24 @@

import logger from '@flex-development/grease/utils/logger.util'
import LogLevel from '@flex-development/log/enums/log-level.enum'
import { trext } from '@trext/plugins/trext.plugin'
import type { TrextOptions } from '@flex-development/trext'
import { trext } from '@flex-development/trext'
import ncc from '@vercel/ncc'
import fs from 'fs-extra'
import path from 'path'
import replace from 'replace-in-file'
import sh from 'shelljs'
import type { BuildOptions as TsBuildOptions, TsConfig } from 'tsc-prog'
import tsc from 'tsc-prog'
import { loadSync as tsconfigLoad } from 'tsconfig/dist/tsconfig'
import type { Argv } from 'yargs'
import yargs from 'yargs'
import { hideBin } from 'yargs/helpers'
import exec from '../helpers/exec'
import fixNodeModulePaths from '../helpers/fix-node-module-paths'
import { $PACKAGE, $WORKSPACE, $WORKSPACE_NO_SCOPE } from '../helpers/pkg'
// @ts-expect-error TS2307
import fixImportPaths from '../helpers/fix-import-paths'
import { $PACKAGE, $WNS, $WORKSPACE } from '../helpers/pkg'
import tsconfigCascade from '../helpers/tsconfig-cascade'
// @ts-expect-error ts(2307)
import useDualExports from '../helpers/use-dual-exports.mjs'

/**
Expand All @@ -24,14 +29,14 @@ import useDualExports from '../helpers/use-dual-exports.mjs'

export type BuildOptions = {
/**
* Name of build environment.
* Remove stale build directories.
*
* @default 'production'
* @default true
*/
env?: 'development' | 'production' | 'test'
clean?: boolean

/** @see BuildOptions.env */
e?: BuildOptions['env']
/** @see BuildOptions.clean */
c?: BuildOptions['clean']

/**
* See the commands that running `build` would run.
Expand All @@ -43,6 +48,16 @@ export type BuildOptions = {
/** @see BuildOptions.dryRun */
d?: BuildOptions['dryRun']

/**
* Name of build environment.
*
* @default 'production'
*/
env?: 'development' | 'production' | 'test'

/** @see BuildOptions.env */
e?: BuildOptions['env']

/**
* Specify module build formats.
*
Expand Down Expand Up @@ -97,38 +112,35 @@ export type BuildOptions = {
/** @property {string[]} BUILD_FORMATS - Module build formats */
const BUILD_FORMATS: BuildOptions['formats'] = ['cjs', 'esm', 'types']

/** @property {string[]} BUNDLE_NAMES - Partial bundle names */
const BUNDLE_NAMES: string[] = [
$WORKSPACE_NO_SCOPE,
`${$WORKSPACE_NO_SCOPE}.min`
]

/** @property {string} COMMAND_PACK - Base pack command */
const COMMAND_PACK: string = 'yarn pack'

/** @property {string} CWD - Current working directory */
const CWD: string = process.cwd()

/** @property {string[]} ENV_CHOICES - Build environment options */
const ENV_CHOICES: BuildOptions['env'][] = ['production', 'test', 'development']

/** @property {Argv<BuildOptions>} args - CLI arguments parser */
const args = yargs(hideBin(process.argv))
.usage('$0 [options]')
.option('env', {
alias: 'e',
choices: ENV_CHOICES,
default: 'production',
describe: 'name of build environment',
requiresArg: true,
type: 'string'
.option('clean', {
alias: 'c',
default: true,
describe: 'remove stale build directories',
type: 'boolean'
})
.option('dryRun', {
alias: 'd',
default: false,
describe: 'see the commands that running `build` would run',
type: 'boolean'
})
.option('env', {
alias: 'e',
choices: ['production', 'test', 'development'],
default: 'production',
describe: 'name of build environment',
requiresArg: true,
type: 'string'
})
.option('formats', {
alias: 'f',
choices: BUILD_FORMATS,
Expand Down Expand Up @@ -176,11 +188,13 @@ const argv = args.argv as BuildOptions
* @return {Promise<void>} Empty promise when complete
*/
async function build(): Promise<void> {
const { dryRun, env, formats = [], tarball } = argv

// Log workflow start
logger(
argv,
'starting build workflow',
[$WORKSPACE, `[dry=${argv.dryRun}]`],
[$WORKSPACE, `[dry=${dryRun}]`],
LogLevel.INFO
)

Expand All @@ -190,52 +204,64 @@ async function build(): Promise<void> {
logger(argv, `set ${argv.env} environment variables`)

// Build project, convert output extensions, create bundles
for (const format of argv.formats ?? []) {
// Get tsconfig config file
const tsconfig: string = `tsconfig.prod.${format}.json`

// Remove stale directory
exec(`rimraf ${format}`, argv.dryRun)
logger(argv, `remove stale ${format} directory`)

// Run build command
if (exec(`tsc -p ${tsconfig}`, argv.dryRun) || argv.dryRun) {
// ! Add ESM-compatible export statement to `exports.default` statements
if (format === 'cjs') useDualExports([`./${format}/**`] as never[])
logger(argv, `build ${format}`)
for (const format of formats) {
// Get build options
// See: https://github.com/jeremyben/tsc-prog
const options: TsBuildOptions = {
...((): TsConfig => {
const { compilerOptions, exclude } = tsconfigCascade([
[CWD, 'json'],
[CWD, 'prod.json'],
[CWD, `prod.${format}.json`]
])

return {
compilerOptions,
exclude,
include: tsconfigLoad(CWD, 'tsconfig.prod.json').config.include
}
})(),
basePath: CWD,
clean: { outDir: argv.clean || undefined }
}

// Build project
!dryRun && tsc.build(options)
!dryRun && format === 'cjs' && useDualExports(`./${format}/**`)
dryRun && logger(argv, `build ${format}`)

// Fix node module import paths
fixNodeModulePaths()
fixImportPaths()

if (format !== 'types') {
// Get trext options
const trext_options = {
// Get extension transformation options
const trext_opts: TrextOptions<'js', 'cjs' | 'mjs'> = {
babel: { sourceMaps: 'inline' as const },
from: 'js',
pattern: /.js$/,
to: `${format === 'cjs' ? 'c' : 'm'}js`
}

// Convert TypeScript output to .cjs or .mjs
!argv.dryRun && (await trext(`${format}/`, trext_options))
logger(argv, `use .${trext_options.to} extensions`)
!dryRun && (await trext<'js' | 'cjs' | 'mjs'>(`${format}/`, trext_opts))
logger(argv, `use .${trext_opts.to} extensions`)

// Create bundles
const BUNDLES = BUNDLE_NAMES.map(async name => {
const bundle = `${format}/${name}.${trext_options.to}`
const filename = 'src/index.ts'
// See: https://github.com/vercel/ncc
const BUNDLES = [$WNS, `${$WNS}.min`].map(async name => {
const bundle = `${format}/${name}.${trext_opts.to}`
const filename = `${format}/index.${trext_opts.to}`
const minify = path.extname(name) === '.min'

if (!argv.dryRun) {
if (!dryRun) {
const { code } = await ncc(`${CWD}/${filename}`, {
esm: format === 'esm',
externals: Object.keys($PACKAGE?.peerDependencies ?? {}),
filename,
minify: minify,
production: argv.env === 'production',
production: env === 'production',
quiet: true,
target: format === 'cjs' ? 'es5' : 'es2020'
target: options.compilerOptions?.target
})

await fs.writeFile(bundle, code, { flag: 'wx+' })
Expand All @@ -256,8 +282,8 @@ async function build(): Promise<void> {
}

// Pack project
if (argv.tarball) {
const { dryRun, out: outFile, install, prepack } = argv
if (tarball) {
const { install, out: outFile, prepack } = argv

// Pack command flags
const flags = [
Expand Down
6 changes: 3 additions & 3 deletions tools/cli/release.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { inspect } from 'util'
import type { Argv } from 'yargs'
import yargs from 'yargs'
import { hideBin } from 'yargs/helpers'
import { $WORKSPACE, $WORKSPACE_NO_SCOPE } from '../helpers/pkg'
import { $WNS, $WORKSPACE } from '../helpers/pkg'

/**
* @file CLI - Release Workflow
Expand Down Expand Up @@ -146,7 +146,7 @@ const options: IGreaseOptions = {
commitAll: true,
gitTagFallback: false,
gitdir: process.env.PROJECT_CWD,
lernaPackage: $WORKSPACE_NO_SCOPE,
lernaPackage: $WNS,
releaseAssets: ['./*.tgz'],
releaseBranchWhitelist: ['release/*'],
releaseCommitMessageFormat: `release: ${$WORKSPACE}@{{currentTag}}`,
Expand All @@ -159,7 +159,7 @@ const options: IGreaseOptions = {
// `continuous-deployment` workflow will create new tag
skip: { tag: true },
skipUnstable: false,
tagPrefix: `${$WORKSPACE_NO_SCOPE}@`,
tagPrefix: `${$WNS}@`,
types: [
/* eslint-disable sort-keys */
{ type: 'feat', section: ':sparkles: Features' },
Expand Down
47 changes: 47 additions & 0 deletions tools/helpers/fix-import-paths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import logger from '@flex-development/grease/utils/logger.util'
import LogLevel from '@flex-development/log/enums/log-level.enum'
import type { ReplaceResult } from 'replace-in-file'
import replace from 'replace-in-file'

/**
* @file Helpers - fixImportPaths
* @module tools/helpers/fixImportPaths
*/

/**
* When using [TypeScript path mapping][1], path aliases are interpreted exactly
* as written. This function fixes all import paths that match either of the
* following regex patterns:
*
* - `/(../.*)?node_modules/g`
* - `/@packages/g`
*
* @see https://github.com/adamreisnz/replace-in-file
*
* [1]: https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
*
* @param {string} [message] - Success log message
* @param {any[]} [args=[]] - Success log arguments
* @return {ReplaceResult[]} Replacement results
*/
const fixImportPaths = (
message?: string,
args: any[] = []
): ReplaceResult[] => {
let results: ReplaceResult[] = []

try {
results = replace.sync({
files: ['./cjs/**/*', './esm/**/*', './types/**/*'],
from: new RegExp(`(../.*)?${process.env.NODE_MODULES}/`),
to: ''
})
} catch (error) {
logger({}, (error as Error).message, [], LogLevel.ERROR)
}

if (message) logger({}, message, args)
return results
}

export default fixImportPaths
47 changes: 0 additions & 47 deletions tools/helpers/fix-node-module-paths.ts

This file was deleted.

10 changes: 8 additions & 2 deletions tools/helpers/pkg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,18 @@ const pkg = (cwd: string = process.cwd()): PackageJson => {
export const $PACKAGE: PackageJson = pkg()

/** @property {string} $VERSION - Package version */
export const $VERSION: string = $PACKAGE.version as string
export const $VERSION: string = pkg().version as string

/** @property {string} $WORKSPACE - Name of NPM package */
export const $WORKSPACE: string = process.env.npm_package_name as string

/** @property {string} name_no_scope - Package name without scope */
export const $WORKSPACE_NO_SCOPE: string = $WORKSPACE.split('/')[1]
export const $WNS: string = $WORKSPACE.split('/')[1]

/** @property {string} $ORG - Organization name (without `@` symbol) */
export const $ORG: string = $WORKSPACE.split('/')[0].slice(1)

/** @property {string} $WID - Normalized package name */
export const $WID: string = `${$ORG}-${$WNS}`

export default pkg
Loading

0 comments on commit a14fd44

Please sign in to comment.