使节点应用程序在 NX 工作区中可执行

Ste*_*son 7 shebang command-line-interface node.js typescript nrwl-nx

我真的很喜欢NX 工作区的结构,这促使我在构建新的 CLI 项目时开始使用它。

我开始创建一个,@nrwl/node:application但目前我在使其可执行时遇到一些问题。

我相信这不是 NX 本身的问题,但我无法#!/usr/bin/env node在 main.ts 文件中添加 shebang,因为 tsc 转译器会抱怨。

Module parse failed: Unexpected character '#' (1:0) File was processed
with these loaders:  * ./node_modules/ts-loader/index.js
Run Code Online (Sandbox Code Playgroud)

我已"bin": {"cli": "main.js"}在 package.json 文件中添加了该属性,但如果我在没有 shebang 的情况下运行 main.js 文件,我将收到此错误:

line 1: syntax error near unexpected token `('
C:\Users\*\AppData\Roaming\npm/node_modules/*/dist/apps/*/main.js: line 1: `(function(e, a) { for(var i in a) e[i] = a[i]; }(exports, /******/ (function(modules) { // webpackBootstrap
Run Code Online (Sandbox Code Playgroud)

有什么聪明的方法可以解决这个问题吗?

重现步骤:

  1. npx create-nx-workspace@latest cli-workspace --preset empty --cli nx --nx-cloud false
  2. cd cli-workspace
  3. npm install -D @nrwl/node
  4. nx generate @nrwl/node:application my-cli
  5. 添加#!/usr/bin/env node到 main.ts 文件的顶部
  6. npm start

小智 2

我也遇到过同样的问题。我可以通过使用@nx-extend/gcp-functions:build构建器构建应用程序来解决这个问题,然后我创建了一个自定义执行器来将应用程序安装为 CLI 工具。

import { ExecutorContext } from '@nrwl/devkit';
import { exec } from 'child_process';
import { promisify } from 'util';
import * as fs from 'fs';

export interface NodeInstallOptions {
    buildPath: string;
    appName: string;
}

export default async function nodeInstallExecutor(
    options: NodeInstallOptions,
    context: ExecutorContext
) {
    let success = true;

    const mainPath = `${options.buildPath}/main.js`;

    console.log('Building library...');
    await runBashLine(success, `nx build ${options.appName}`);

    console.log('Adding shebang line to main.js...');
    const file = fs.readFileSync(mainPath, 'utf8');
    const first_line = file.split("\n")[0];
    if (first_line !== '#!/usr/bin/env node') {
        var data = "#!/usr/bin/env node\n\n";
        data += fs.readFileSync(mainPath, 'utf8');
        fs.writeFileSync(mainPath, data);
    }

    console.log("Packing library...")
    await runBashLine(success, `cd ${options.buildPath}; npm pack`);

    console.log('Installing library...');
    await runBashLine(success, `npm install -g ${options.buildPath}/*.tgz`);

    return { success };
}

async function runBashLine(success: boolean, line: string) {
    const { stdout, stderr } = await promisify(exec)(line);
    console.log(stdout);
    console.error(stderr);

    success = success && !stderr;
}
Run Code Online (Sandbox Code Playgroud)