From aae90bbbe06fc2d4de4b14f5b724b254731f9065 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Mon, 4 May 2020 08:57:39 -0400 Subject: [PATCH] Set CommonJS module format when transpiling TS code (#7197) --- .../1_typescript_support_spec.ts.js | 17 +++++++++ .../server/lib/plugins/child/run_plugins.js | 22 ++++++----- packages/server/lib/plugins/resolve.js | 4 ++ packages/server/lib/project.js | 12 +++--- packages/server/lib/util/ts-node-options.js | 29 ++++++++++++++ .../test/e2e/1_typescript_support_spec.ts | 17 +++++++++ .../ts-proj-with-own-tsconfig/cypress.json | 1 + .../cypress/integration/app_spec.ts | 5 +++ .../cypress/integration/js-spec.js | 11 ++++++ .../cypress/integration/math.ts | 3 ++ .../cypress/plugins/greeting.ts | 3 ++ .../cypress/plugins/index.ts | 8 ++++ .../cypress/support/commands.ts | 6 +++ .../cypress/support/index.ts | 20 ++++++++++ .../ts-proj-with-own-tsconfig/tsconfig.json | 6 +++ packages/server/test/unit/project_spec.js | 4 ++ yarn.lock | 38 +++++++++++-------- 17 files changed, 175 insertions(+), 31 deletions(-) create mode 100644 packages/server/lib/util/ts-node-options.js create mode 100644 packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress.json create mode 100644 packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/app_spec.ts create mode 100644 packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/js-spec.js create mode 100644 packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/math.ts create mode 100644 packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/plugins/greeting.ts create mode 100644 packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/plugins/index.ts create mode 100644 packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/commands.ts create mode 100644 packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/index.ts create mode 100644 packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/tsconfig.json diff --git a/packages/server/__snapshots__/1_typescript_support_spec.ts.js b/packages/server/__snapshots__/1_typescript_support_spec.ts.js index 819c78e305ed..3363bf4d83ca 100644 --- a/packages/server/__snapshots__/1_typescript_support_spec.ts.js +++ b/packages/server/__snapshots__/1_typescript_support_spec.ts.js @@ -225,3 +225,20 @@ exports['e2e typescript project passes 1'] = ` ` + +exports['typescript with tsconfig run'] = ` + (Run Finished) + + + Spec Tests Passing Failing Pending Skipped + ┌────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ ✔ app_spec.ts XX:XX 1 1 - - - │ + ├────────────────────────────────────────────────────────────────────────────────────────────────┤ + │ ✔ js-spec.js XX:XX 2 2 - - - │ + ├────────────────────────────────────────────────────────────────────────────────────────────────┤ + │ ✔ math.ts XX:XX - - - - - │ + └────────────────────────────────────────────────────────────────────────────────────────────────┘ + ✔ All specs passed! XX:XX 3 3 - - - + + +` diff --git a/packages/server/lib/plugins/child/run_plugins.js b/packages/server/lib/plugins/child/run_plugins.js index 07311aed183b..1f70bb3f2706 100644 --- a/packages/server/lib/plugins/child/run_plugins.js +++ b/packages/server/lib/plugins/child/run_plugins.js @@ -12,6 +12,7 @@ const preprocessor = require('./preprocessor') const task = require('./task') const util = require('../util') const validateEvent = require('./validate_event') +const tsNodeOptions = require('../../util/ts-node-options') const ARRAY_METHODS = ['concat', 'push', 'unshift', 'slice', 'pop', 'shift', 'slice', 'splice', 'filter', 'map', 'forEach', 'reduce', 'reverse', 'splice', 'includes'] @@ -160,6 +161,10 @@ let tsRegistered = false module.exports = (ipc, pluginsFile, projectRoot) => { debug('pluginsFile:', pluginsFile) + debug('project root:', projectRoot) + if (!projectRoot) { + throw new Error('Unexpected: projectRoot should be a string') + } process.on('uncaughtException', (err) => { debug('uncaught exception:', util.serializeError(err)) @@ -180,21 +185,18 @@ module.exports = (ipc, pluginsFile, projectRoot) => { if (!tsRegistered) { try { const tsPath = resolve.sync('typescript', { - basedir: this.projectRoot, + basedir: projectRoot, }) - debug('typescript path: %s', tsPath) + const tsOptions = tsNodeOptions.getTsNodeOptions(tsPath) - tsnode.register({ - compiler: tsPath, - transpileOnly: true, - compilerOptions: { + debug('typescript path: %s', tsPath) + debug('registering plugins TS with options %o', tsOptions) - esModuleInterop: true, - }, - }) + tsnode.register(tsOptions) } catch (e) { - debug(`typescript doesn't exist. ts-node setup passed.`) + debug(`typescript doesn't exist. ts-node setup failed.`) + debug('error message: %s', e.message) } // ensure typescript is only registered once diff --git a/packages/server/lib/plugins/resolve.js b/packages/server/lib/plugins/resolve.js index b27129098c2d..ddc216644b7a 100644 --- a/packages/server/lib/plugins/resolve.js +++ b/packages/server/lib/plugins/resolve.js @@ -19,6 +19,10 @@ module.exports = { basedir: config.projectRoot, } + if (!config.projectRoot) { + throw new Error('Config is missing projet root') + } + debug('resolving typescript with options %o', options) const resolved = resolve.sync('typescript', options) diff --git a/packages/server/lib/project.js b/packages/server/lib/project.js index 616acdf955b5..e56b34bbc108 100644 --- a/packages/server/lib/project.js +++ b/packages/server/lib/project.js @@ -31,6 +31,7 @@ const keys = require('./util/keys') const settings = require('./util/settings') const specsUtil = require('./util/specs') const { escapeFilenameInUrl } = require('./util/escape_filename') +const tsNodeOptions = require('./util/ts-node-options') const localCwd = cwd() @@ -107,14 +108,15 @@ class Project extends EE { basedir: this.projectRoot, }) + const tsOptions = tsNodeOptions.getTsNodeOptions(tsPath) + debug('typescript path: %s', tsPath) + debug('registering project TS with options %o', tsOptions) - tsnode.register({ - compiler: tsPath, - transpileOnly: true, - }) + tsnode.register(tsOptions) } catch (e) { - debug(`typescript doesn't exist. ts-node setup passed.`) + debug(`typescript doesn't exist. ts-node setup failed.`) + debug('error message %s', e.message) } return cfg diff --git a/packages/server/lib/util/ts-node-options.js b/packages/server/lib/util/ts-node-options.js new file mode 100644 index 000000000000..de72ee032712 --- /dev/null +++ b/packages/server/lib/util/ts-node-options.js @@ -0,0 +1,29 @@ +// returns options for ts-node registration +// https://github.com/TypeStrong/ts-node +const _ = require('lodash') + +/** + * Default ts - node options.We want to output CommonJS modules. + * And we want to run fast - thus transpile only mode (no type checking) +*/ +const tsOptions = { + transpileOnly: true, + compilerOptions: { + module: 'CommonJS', + esModuleInterop: true, + }, +} + +/** + * Returns combined object with ts-node options. + * @param {string} tsPath Path to TypeScript + */ +function getTsNodeOptions (tsPath) { + const merged = _.cloneDeep(tsOptions) + + merged.compiler = tsPath + + return merged +} + +module.exports = { getTsNodeOptions } diff --git a/packages/server/test/e2e/1_typescript_support_spec.ts b/packages/server/test/e2e/1_typescript_support_spec.ts index a35736db1b82..1e500222780e 100644 --- a/packages/server/test/e2e/1_typescript_support_spec.ts +++ b/packages/server/test/e2e/1_typescript_support_spec.ts @@ -1,6 +1,8 @@ const e2e = require('../support/helpers/e2e') const Fixtures = require('../support/helpers/fixtures') +const snapshot = require('snap-shot-it') + describe('e2e typescript', function () { e2e.setup({ npmInstall: true }) @@ -27,4 +29,19 @@ describe('e2e typescript', function () { snapshot: true, }) }) + + it('handles tsconfig with module other than commonjs', function () { + const projPath = Fixtures.projectPath('ts-proj-with-own-tsconfig') + + return e2e.exec(this, { + project: projPath, + config: { + video: false, + }, + }).then((result) => { + const runSummary = e2e.leaveRunFinishedTable(e2e.normalizeStdout(result.stdout)) + + snapshot('typescript with tsconfig run', runSummary) + }) + }) }) diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress.json b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress.json @@ -0,0 +1 @@ +{} diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/app_spec.ts b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/app_spec.ts new file mode 100644 index 000000000000..d539f78bfb6f --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/app_spec.ts @@ -0,0 +1,5 @@ +import { add } from './math' + +it('is true', () => { + expect(add(1, 2)).to.eq(3) +}) diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/js-spec.js b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/js-spec.js new file mode 100644 index 000000000000..1f7c6d518cc5 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/js-spec.js @@ -0,0 +1,11 @@ +import { add } from './math' + +describe('JS spec', () => { + it('adds 2 and 2 together', () => { + expect(add(2, 2)).to.equal(4) + }) + + it('calls task', () => { + cy.task('hello', 'TS').should('equal', 'Hello, TS!') + }) +}) diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/math.ts b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/math.ts new file mode 100644 index 000000000000..e29e78dc31cf --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/math.ts @@ -0,0 +1,3 @@ +export const add = (a: number, b: number) => { + return a + b +} diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/plugins/greeting.ts b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/plugins/greeting.ts new file mode 100644 index 000000000000..eaa232c40687 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/plugins/greeting.ts @@ -0,0 +1,3 @@ +export const asyncGreeting = async (greeting) => { + return Promise.resolve(`Hello, ${greeting}!`) +} diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/plugins/index.ts b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/plugins/index.ts new file mode 100644 index 000000000000..0604644e4ed2 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/plugins/index.ts @@ -0,0 +1,8 @@ +/// +import { asyncGreeting } from './greeting' + +export default (on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) => { + on('task', { + hello: asyncGreeting, + }) +} diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/commands.ts b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/commands.ts new file mode 100644 index 000000000000..176bf41439f4 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/commands.ts @@ -0,0 +1,6 @@ +/// + +// Copied an example command from https://on.cypress.io/custom-commands +Cypress.Commands.add('clickLink', (label: string | number | RegExp) => { + cy.get('a').contains(label).click() +}) diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/index.ts b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/index.ts new file mode 100644 index 000000000000..d68db96df269 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/index.ts @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/tsconfig.json b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/tsconfig.json new file mode 100644 index 000000000000..e9490e1e3e20 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "module": "esnext", + "importHelpers": true + } +} diff --git a/packages/server/test/unit/project_spec.js b/packages/server/test/unit/project_spec.js index 6de18e3470bd..982272fd2961 100644 --- a/packages/server/test/unit/project_spec.js +++ b/packages/server/test/unit/project_spec.js @@ -351,6 +351,10 @@ This option will not have an effect in Some-other-name. Tests that rely on web s expect(register).to.be.calledWith({ transpileOnly: true, compiler: projTsPath, + compilerOptions: { + module: 'CommonJS', + esModuleInterop: true, + }, }) }) }) diff --git a/yarn.lock b/yarn.lock index 6207498be1ff..2a47328c0438 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5483,9 +5483,9 @@ aws-sdk@2.447.0: xml2js "0.4.19" aws-sdk@^2.389.0: - version "2.666.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.666.0.tgz#4cd4f6bea920e3ef3192bf113aa9c606a307a709" - integrity sha512-m4m4eHs/F7SRW0OnvxRWyrAyqcQE7kyVnfwyrhA7P0w92FOmmu+tw6JKI5LZNVBsaj2VBAfPn72V6nWzP3IIlw== + version "2.667.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.667.0.tgz#9d45b5fe90038bfba88a892112251d87af19b2f5" + integrity sha512-CDeMyqblfGlj/xUSp1/G1b9Tb4LDTid5CYrBW9FyBqMg6JIiXkaEN3b4oK2VjS18Xv1eth5LJAbYNMxjfHfKjw== dependencies: buffer "4.9.1" events "1.1.1" @@ -10227,9 +10227,9 @@ electron-publish@22.3.6: mime "^2.4.4" electron-to-chromium@^1.3.413: - version "1.3.425" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.425.tgz#96b7b5aa9115e42baf59be88d2432c9f406128c4" - integrity sha512-JTEOWiqCY4snuKuQAaFy0z6LK2Gdb8Lojkd/csQwpNHgMUF8I6QRjGVKk44IH46dHQhUFKzr4o6zxZrtDBjc2Q== + version "1.3.426" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.426.tgz#d7301de9e40df83a40fe1f51b4463cfe170d1153" + integrity sha512-sdQ7CXQbFflKY5CU63ra+kIYq9F7d1OqI33856qJZxTrwo0sLASdmoRl9lWpGrQDS9Nk/RFliQWd3PPDrZ+Meg== electron@8.2.3: version "8.2.3" @@ -13252,12 +13252,13 @@ has@^1.0.0, has@^1.0.3: function-bind "^1.1.1" hash-base@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" - integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" hash.js@^1.0.0, hash.js@^1.0.3: version "1.1.7" @@ -17531,11 +17532,16 @@ module-not-found-error@^1.0.0: resolved "https://registry.yarnpkg.com/module-not-found-error/-/module-not-found-error-1.0.1.tgz#cf8b4ff4f29640674d6cdd02b0e3bc523c2bbdc0" integrity sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA= -moment@2.24.0, moment@^2.18.1, moment@^2.19.1, moment@^2.9.0: +moment@2.24.0: version "2.24.0" resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== +moment@^2.18.1, moment@^2.19.1, moment@^2.9.0: + version "2.25.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.25.0.tgz#e961ab9a5848a1cf2c52b1af4e6c82a8401e7fe9" + integrity sha512-vbrf6kJGpevOxmDRvCCvGuCSXvRj93264WcFzjm3Z3pV4lfjrXll8rvSP+EbmCte64udj1LkJMILxQnjXAQBzg== + moo@^0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.1.tgz#7aae7f384b9b09f620b6abf6f74ebbcd1b65dbc4" @@ -20541,7 +20547,7 @@ read@1, read@~1.0.1: string_decoder "~1.1.1" util-deprecate "~1.0.1" -"readable-stream@2 || 3", readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0: +"readable-stream@2 || 3", readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -23992,9 +23998,9 @@ typescript@^3.0.3, typescript@^3.6.4: integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== typescript@next: - version "4.0.0-dev.20200430" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.0-dev.20200430.tgz#4316bdb47f9c7339f3c6155a7430b461bc62b595" - integrity sha512-cF8I0/7zTJqcgh2Xo8D85qKXHJb5Sy74Y6emU6tKvydqhey0BhEwd4BgnOqW9vP8+ZMGioRYfED1lIzZN4g9dg== + version "4.0.0-dev.20200501" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.0-dev.20200501.tgz#9a54727bd719102d947a5ecf584ccc985dccb94b" + integrity sha512-RQvw3/R3//3hNxzeTJ4sbiuX9qjrpoIU6VxD+QquHHaJXf67P3yfIcV9hNFqd2QvrUiFPGM3KN08ahWkEN56bA== ua-parser-js@^0.7.18: version "0.7.21"