-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fffe2e1
commit c2ec903
Showing
10 changed files
with
465 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@rnm/tscx": patch | ||
--- | ||
|
||
feat: init |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,67 @@ | ||
# tscx(WIP) | ||
# TSCX | ||
|
||
A tsc wrapper with many convenient features. | ||
[![](https://img.shields.io/npm/l/@rnm/tscx.svg)](https://github.com/rnmjs/tscx/blob/main/LICENSE) | ||
[![](https://img.shields.io/npm/v/@rnm/tscx.svg)](https://www.npmjs.com/package/@rnm/tscx) | ||
[![](https://img.shields.io/npm/dm/@rnm/tscx.svg)](https://www.npmjs.com/package/@rnm/tscx) | ||
[![](https://img.shields.io/librariesio/release/npm/@rnm/tscx)](https://www.npmjs.com/package/@rnm/tscx) | ||
[![](https://packagephobia.com/badge?p=@rnm/tscx)](https://packagephobia.com/result?p=@rnm/tscx) | ||
|
||
A tsc wrapper with many convenient features. Bring the [nodemon](https://www.npmjs.com/package/nodemon) + JavaScript development experience to TypeScript. | ||
|
||
## Background | ||
|
||
When we are using JavaScript, we usually run `nodemon main.js`. Then, application will automatically restart when js file changes. It's a great development experience. Why can't TypeScript? Because of the ts compilation (tsc), some edge cases are hard to use. For example: | ||
|
||
- Remove the output folder before compilation stated | ||
- Copy non-ts files to output folder after compilation finished | ||
- Execute app entrance file immediately once compilation finished | ||
- Watch source files, repeat steps above and restart the app. | ||
|
||
Now you can run one line of command to solve the problems. Better development experience! | ||
|
||
```sh | ||
npx tscx --project tsconfig.build.json --remove --copyfiles --watch --exec bootstrap.js | ||
``` | ||
|
||
Happy hacking! | ||
|
||
## Highlight | ||
|
||
- Same usages as `tsc` with few additional options. | ||
- Remove output folder before before every compilation. | ||
- Copy non-ts files to output folder after every compilation. | ||
- Execute js file after compilation success. | ||
- Respect `tsconfig.json`. | ||
- ESM. | ||
|
||
## Install | ||
|
||
```sh | ||
npm install typescript @nrm/tscx -D | ||
``` | ||
|
||
## Usages | ||
|
||
```sh | ||
# Equivalent to `npx tsc` | ||
$ npx tscx | ||
|
||
# Equivalent to `npx tsc --project tsconfig.build.json --watch` | ||
$ npx tscx --project tsconfig.build.json --watch | ||
|
||
# Remove output folder before before compilation and then compile ts code. | ||
$ npx tscx --remove | ||
|
||
# Compile ts code and then copy non-ts files to output folder after compilation. | ||
$ npx tscx --copyfiles | ||
|
||
# Compile ts code in watch mode and execute bootstrap.js after every compilation success. | ||
$ npx tscx --project tsconfig.build.json --watch --exec bootstrap.js | ||
|
||
# Remove => Compile => Copy => Execute => Edit any file to repeat it | ||
$ npx tscx --project tsconfig.build.json --remove --copyfiles --watch --exec bootstrap.js | ||
``` | ||
|
||
## License | ||
|
||
MIT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import path from "node:path"; | ||
import process from "node:process"; | ||
import chokidar, { type FSWatcher } from "chokidar"; | ||
import { Compiler, type CompilerOptions } from "./compiler.js"; | ||
|
||
interface TscxOptions extends CompilerOptions { | ||
watch: boolean; | ||
} | ||
|
||
export class Action { | ||
private readonly compiler; | ||
private watcher?: FSWatcher; | ||
constructor(private readonly options: TscxOptions) { | ||
this.compiler = new Compiler(options); | ||
} | ||
|
||
private setupWatcher() { | ||
const include = this.compiler.getInclude() ?? []; | ||
const watchFiles = | ||
include.length <= 0 | ||
? [process.cwd()] | ||
: include | ||
.map((i) => path.resolve(process.cwd(), i)) | ||
.concat(path.resolve(process.cwd(), this.options.project)); | ||
|
||
this.watcher = chokidar.watch(watchFiles, { | ||
ignored: ["**/node_modules/**", "**/.git/**", this.compiler.getOutDir()], | ||
ignoreInitial: true, | ||
}); | ||
this.watcher | ||
.on("add", (filepath) => this.cb(filepath)) | ||
.on("unlink", (filepath) => this.cb(filepath)) | ||
.on("change", (filepath) => this.cb(filepath)) | ||
.on("ready", () => this.cb()); | ||
} | ||
|
||
private cb(filepath?: string) { | ||
console.log("Recompile for the file updated", filepath); | ||
if ( | ||
!filepath || | ||
path.resolve(process.cwd(), filepath) !== | ||
path.resolve(process.cwd(), this.options.project) | ||
) { | ||
return this.compiler.exec(); | ||
} | ||
|
||
this.compiler.refreshTsConfig(); | ||
this.watcher | ||
?.close() | ||
.then(() => { | ||
this.setupWatcher(); | ||
}) | ||
.catch((e) => { | ||
console.error("Close watcher fail!", e); | ||
process.exit(1); | ||
}); | ||
} | ||
|
||
start() { | ||
if (!this.options.watch) { | ||
this.compiler.exec(); | ||
return; | ||
} | ||
|
||
this.setupWatcher(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import fs from "node:fs/promises"; | ||
import path from "node:path"; | ||
import { fileURLToPath } from "node:url"; | ||
import { Command } from "commander"; | ||
import { Action } from "../action.js"; | ||
|
||
const version: string = JSON.parse( | ||
await fs.readFile( | ||
path.resolve( | ||
path.dirname(fileURLToPath(import.meta.url)), | ||
"..", | ||
"..", | ||
"package.json", | ||
), | ||
"utf8", | ||
), | ||
).version; | ||
|
||
new Command() | ||
.name("tscx") | ||
.version(version) | ||
.description("The TypeScript Compiler. Run `tsc` under the hood.") | ||
.option( | ||
"-p, --project <path>", | ||
"Compile the project given the path to its configuration file, or to a folder with a 'tsconfig.json'.", | ||
"tsconfig.json", | ||
) | ||
.option("-w, --watch", "Watch input files.", false) | ||
.option( | ||
"-r, --remove", | ||
"Remove output folder before before every compilation.", | ||
false, | ||
) | ||
.option( | ||
"-c, --copyfiles", | ||
"Copy non-ts files to output folder after every compilation.", | ||
false, | ||
) | ||
.option( | ||
"-e, --exec <path>", | ||
"Execute the specified js file after compilation success", | ||
) | ||
.action((options) => { | ||
new Action(options).start(); | ||
}) | ||
.parse(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import fs from "node:fs/promises"; | ||
import path from "node:path"; | ||
import process from "node:process"; | ||
|
||
/** | ||
* Copy non-ts/non-js files to outDir | ||
* @param rootDir absolute path | ||
* @param outDir absolute path | ||
*/ | ||
async function copyfiles(rootDir: string, outDir: string) { | ||
rootDir = path.resolve(rootDir); | ||
outDir = path.resolve(outDir); | ||
async function walkDir(dir: string, cb: (filepath: string) => Promise<void>) { | ||
await Promise.all( | ||
(await fs.readdir(dir)) | ||
.map((filepath) => path.resolve(dir, filepath)) | ||
.map(async (filepath) => { | ||
if ((await fs.stat(filepath)).isDirectory()) { | ||
if ( | ||
filepath !== outDir && | ||
!filepath.endsWith(`${path.sep}node_modules`) | ||
) { | ||
await walkDir(filepath, cb); | ||
} | ||
} else { | ||
if (!/\.(js|cjs|mjs|jsx|ts|cts|mts|tsx)$/.test(filepath)) { | ||
await cb(filepath); | ||
} | ||
} | ||
}), | ||
); | ||
} | ||
await walkDir(rootDir, async (filepath) => { | ||
const dest = filepath.replace(rootDir, outDir); | ||
console.log("Copy", filepath, "=>", dest); | ||
await fs.copyFile(filepath, dest); | ||
}); | ||
} | ||
|
||
const rootDir = process.argv[2]; | ||
const outDir = process.argv[3]; | ||
if (!rootDir || !outDir) { | ||
throw new Error("`rootDir` and `outDir` are required"); | ||
} | ||
|
||
await copyfiles(rootDir, outDir); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { spawn } from "node:child_process"; | ||
import path from "node:path"; | ||
import process from "node:process"; | ||
import { fileURLToPath } from "node:url"; | ||
|
||
const __dirname = path.dirname(fileURLToPath(import.meta.url)); | ||
const REMOVE_PATH = path.resolve(__dirname, "remove.mjs"); | ||
const COPYFILES_PATH = path.resolve(__dirname, "copyfiles.mjs"); | ||
const TSC_PATH = path.resolve( | ||
process.cwd(), | ||
"node_modules", | ||
"typescript", | ||
"bin", | ||
"tsc", | ||
); | ||
|
||
export function remove(filepath: string) { | ||
console.log("Remove", filepath); | ||
return spawn("node", [REMOVE_PATH, filepath], { stdio: "inherit" }); | ||
} | ||
|
||
export function tsc(options: { project: string }) { | ||
console.log("Tsc", options); | ||
return spawn("node", [TSC_PATH, "--project", options.project], { | ||
stdio: "inherit", | ||
}); | ||
} | ||
|
||
export function copyfiles(rootDir: string, outDir: string) { | ||
console.log("Copyfiles", rootDir, "=>", outDir); | ||
return spawn("node", [COPYFILES_PATH, rootDir, outDir], { stdio: "inherit" }); | ||
} | ||
|
||
export function exec(filepath: string) { | ||
console.log("Execute", filepath); | ||
return spawn("node", [filepath], { stdio: "inherit" }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import fs from "node:fs"; | ||
import process from "node:process"; | ||
|
||
/** | ||
* @param filepath absolute filepath | ||
*/ | ||
async function remove(filepath: string) { | ||
await new Promise<void>((resolve, reject) => { | ||
fs.stat(filepath, (err) => { | ||
if (err) { | ||
return err.code === "ENOENT" ? resolve() : reject(err); // do nothing if file not found | ||
} | ||
fs.rm(filepath, { recursive: true }, (e) => (e ? reject(e) : resolve())); | ||
}); | ||
}); | ||
console.log(`Removed ${filepath}`); | ||
} | ||
|
||
const filepath = process.argv[2]; | ||
if (!filepath) { | ||
throw new Error("File path is required"); | ||
} | ||
|
||
await remove(filepath); |
Oops, something went wrong.