From 28b576967cd54380a70f045b4eda06fc80d45b71 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 6 Apr 2020 15:36:38 +0200 Subject: [PATCH] packages/cli: make src-relative imports work --- packages/cli/bin/backstage-cli | 48 +++++++++++++++++++++++++++++++ packages/cli/config/jest.js | 4 ++- packages/cli/package.json | 3 +- packages/cli/src/helpers/paths.ts | 16 ++++++++++- packages/cli/tsconfig.json | 9 ++---- yarn.lock | 17 ++++++++++- 6 files changed, 87 insertions(+), 10 deletions(-) diff --git a/packages/cli/bin/backstage-cli b/packages/cli/bin/backstage-cli index b7317db25b..a47851bf03 100755 --- a/packages/cli/bin/backstage-cli +++ b/packages/cli/bin/backstage-cli @@ -5,12 +5,60 @@ const path = require('path'); // Figure out whether we're running inside the backstage repo or as an installed dependency const isLocal = require('fs').existsSync(path.resolve(__dirname, '../src')); if (!isLocal) { + // src-relative imports are a pain to get to work with plain tsc compilation, as the + // transpiled code will maintain the imports as they are in the source. Which means an + // import for `helpers/paths` will start like that in the output, which won't work in NodeJS. + // + // This is a solution for getting src-relative imports to work with typescript/node in + // the published package. We're using `module: "amd"` to ship the entire cli implementation + // in one file, and it also happens to generate correct module definition and import statements. + + // Minimal AMD implementation + const moduleFactories = {}; + const moduleCache = {}; + global.define = (name, deps, moduleFunc) => { + moduleFactories[name] = () => { + const exportsObj = {}; + const impls = deps.slice(2).map(dep => { + const factory = moduleFactories[dep]; + if (!factory) { + return require(dep); + } + if (!moduleCache[dep]) { + moduleCache[dep] = factory(); + } + return moduleCache[dep]; + }); + + moduleFunc(require, exportsObj, ...impls); + + return exportsObj; + }; + }; require('../dist'); + + // index module is the entrypoint + moduleFactories.index(); } else { + const tsConfigPath = path.resolve(__dirname, '../tsconfig.json'); + const { + baseUrl: relativeBaseUrl, + paths = {}, + } = require(tsConfigPath).compilerOptions; + const baseUrl = path.resolve(__dirname, '..', relativeBaseUrl); + + // Use tsconfig-paths to resolve src-relative paths during development + const cleanupPaths = require('tsconfig-paths').register({ baseUrl, paths }); + require('ts-node').register({ project: path.resolve(__dirname, '../tsconfig.json'), + compilerOptions: { + module: 'CommonJS', + }, transpileOnly: true, }); require('../src'); + + cleanupPaths(); } diff --git a/packages/cli/config/jest.js b/packages/cli/config/jest.js index e443ceec1b..055c3e73c5 100644 --- a/packages/cli/config/jest.js +++ b/packages/cli/config/jest.js @@ -24,7 +24,9 @@ if (fs.existsSync('jest.config.js')) { } else if (fs.existsSync('jest.config.ts')) { module.exports = require(path.resolve('jest.config.ts')); } else { - const extraOptions = {}; + const extraOptions = { + modulePaths: [''], + }; // Use src/setupTests.ts as the default location for configuring test env if (fs.existsSync('src/setupTests.ts')) { diff --git a/packages/cli/package.json b/packages/cli/package.json index a430cc851c..6b6f489575 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -39,7 +39,8 @@ "@types/webpack-dev-server": "^3.10.0", "del": "^5.1.0", "nodemon": "^2.0.2", - "ts-node": "^8.6.2" + "ts-node": "^8.6.2", + "tsconfig-paths": "^3.9.0" }, "bin": { "backstage-cli": "bin/backstage-cli" diff --git a/packages/cli/src/helpers/paths.ts b/packages/cli/src/helpers/paths.ts index f49bfa9689..746b3f6ea8 100644 --- a/packages/cli/src/helpers/paths.ts +++ b/packages/cli/src/helpers/paths.ts @@ -77,8 +77,22 @@ export function findRootPath(topPath: string): string { ); } +// Finds the root of the cli package itself +export function findOwnDir() { + // Known relative locations of package in dist/dev + const pathDist = '..'; + const pathDev = '../..'; + + // Check the closest dir first + const pkgInDist = resolvePath(__dirname, pathDist, 'package.json'); + const isDist = fs.pathExistsSync(pkgInDist); + + const path = isDist ? pathDist : pathDev; + return resolvePath(__dirname, path); +} + export function findPaths(): Paths { - const ownDir = resolvePath(__dirname, '../..'); + const ownDir = findOwnDir(); const targetDir = fs.realpathSync(process.cwd()); // We're not always running in a monorepo, so we lazy init this to only crash commands diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json index e30150dda7..8c7fb90d47 100644 --- a/packages/cli/tsconfig.json +++ b/packages/cli/tsconfig.json @@ -2,11 +2,8 @@ "extends": "../../tsconfig.json", "include": ["src"], "compilerOptions": { - "outDir": "dist", - "module": "CommonJS", - "baseUrl": "src", - "paths": { - "*": ["src/*"] - } + "outFile": "dist/index.js", + "module": "amd", + "baseUrl": "src" } } diff --git a/yarn.lock b/yarn.lock index 402e134b3c..73c20c3a2c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3657,6 +3657,11 @@ resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + "@types/mime@*": version "2.0.1" resolved "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" @@ -16919,7 +16924,7 @@ request@^2.85.0, request@^2.87.0, request@^2.88.0: tunnel-agent "^0.6.0" uuid "^3.3.2" -request@cypress-io/request#b5af0d1fa47eec97ba980cde90a13e69a2afcd16: +"request@github:cypress-io/request#b5af0d1fa47eec97ba980cde90a13e69a2afcd16": version "2.88.1" resolved "https://codeload.github.com/cypress-io/request/tar.gz/b5af0d1fa47eec97ba980cde90a13e69a2afcd16" dependencies: @@ -18987,6 +18992,16 @@ ts-pnp@1.1.6, ts-pnp@^1.1.2, ts-pnp@^1.1.6: resolved "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.6.tgz#389a24396d425a0d3162e96d2b4638900fdc289a" integrity sha512-CrG5GqAAzMT7144Cl+UIFP7mz/iIhiy+xQ6GGcnjTezhALT02uPMRw7tgDSESgB5MsfKt55+GPWw4ir1kVtMIQ== +tsconfig-paths@^3.9.0: + version "3.9.0" + resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" + integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.0" + strip-bom "^3.0.0" + tslib@1.10.0: version "1.10.0" resolved "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"