feat(typescript): detect typescript based on `tsconfig.json` (#5412)

This commit is contained in:
Pooya Parsa 2019-03-29 23:49:30 +04:30 committed by GitHub
parent 82bde15622
commit 6ffc5c5792
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 124 additions and 65 deletions

View File

@ -1,29 +1,34 @@
{
"name": "nuxt.js",
"private": true,
"repository": {
"type": "git",
"url": "git+https://github.com/nuxt/nuxt.js.git"
},
"workspaces": [
"packages/*",
"distributions/*"
],
"scripts": {
"build": "yarn clean && yarn pkg",
"pkg": "node -r esm ./scripts/package",
"clean": "yarn clean:build && yarn clean:examples && yarn clean:test",
"clean:build": "rimraf distributions/*/dist packages/*/dist",
"clean:examples": "rimraf examples/*/dist examples/*/.nuxt",
"clean:test": "rimraf test/fixtures/*/dist test/fixtures/*/.nuxt*/",
"dev": "node -r esm ./scripts/dev.js",
"coverage": "codecov",
"dev": "node -r esm ./scripts/dev.js",
"postinstall": "lerna link && yarn dev",
"lint": "eslint --ext .js,.mjs,.vue .",
"lint:app": "eslint-multiplexer eslint --ignore-path packages/vue-app/template/.eslintignore 'test/fixtures/!(missing-plugin)/.nuxt!(-dev)/**' | eslint-multiplexer -b",
"nuxt": "node -r esm ./packages/cli/bin/nuxt-cli.js",
"pkg": "node -r esm ./scripts/package",
"release": "./scripts/release",
"test": "yarn test:fixtures && yarn test:unit && yarn test:types",
"test:fixtures": "jest test/fixtures --forceExit",
"test:e2e": "jest -i test/e2e --forceExit",
"test:fixtures": "jest test/fixtures --forceExit",
"test:lint": "yarn lint",
"test:unit": "jest test/unit packages --forceExit",
"test:types": "tsc -p test/types",
"postinstall": "lerna link && yarn dev",
"release": "./scripts/release"
"test:unit": "jest test/unit packages --forceExit"
},
"devDependencies": {
"@babel/core": "^7.4.0",
@ -79,14 +84,10 @@
"sort-package-json": "^1.22.1",
"ts-jest": "^24.0.0",
"ts-loader": "^5.3.3",
"ts-node": "^8.0.3",
"tslint": "^5.14.0",
"typescript": "^3.4.1",
"vue-jest": "^4.0.0-beta.2",
"vue-property-decorator": "^8.1.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/nuxt/nuxt.js.git"
},
"name": "nuxt.js"
}
}

View File

@ -20,6 +20,7 @@
"esm": "^3.2.22",
"execa": "^1.0.0",
"exit": "^0.1.2",
"fs-extra": "^7.0.1",
"minimist": "^1.2.0",
"opener": "1.5.1",
"pretty-bytes": "^5.1.0",

View File

@ -6,7 +6,7 @@ import { name, version } from '../package.json'
import { loadNuxtConfig, forceExit } from './utils'
import { indent, foldLines, colorize } from './utils/formatting'
import { startSpaces, optionSpaces, forceExitTimeout } from './utils/constants'
import { detectAndSetupTypeScriptSupport } from './utils/typescript'
import { detectTypeScript } from './utils/typescript'
import * as imports from './imports'
export default class NuxtCommand {
@ -92,7 +92,11 @@ export default class NuxtCommand {
async getNuxtConfig(extraOptions = {}) {
const rootDir = path.resolve(this.argv._[0] || '.')
extraOptions._typescript = await detectAndSetupTypeScriptSupport(rootDir, { transpileOnly: this.cmd.name === 'start' })
// Typescript support
extraOptions._typescript = await detectTypeScript(rootDir, {
transpileOnly: this.cmd.name === 'start'
})
const config = await loadNuxtConfig(this.argv)
const options = Object.assign(config, extraOptions)

View File

@ -29,4 +29,8 @@ export const builder = () => _import('@nuxt/builder')
export const webpack = () => _import('@nuxt/webpack')
export const generator = () => _import('@nuxt/generator')
export const core = () => _import('@nuxt/core')
export const tsNode = () => _import('ts-node')
export const nuxtTypescript = () => _import('@nuxt/typescript')
export const importModule = _import

View File

@ -1,20 +1,49 @@
import path from 'path'
import consola from 'consola'
import fs from 'fs-extra'
import * as imports from '../imports'
export async function detectAndSetupTypeScriptSupport(rootDir, options = {}) {
async function registerTSNode(tsConfigPath, options) {
const { register } = await imports.tsNode()
// https://github.com/TypeStrong/ts-node
register({
project: tsConfigPath,
compilerOptions: {
module: 'commonjs'
},
...options
})
}
async function getNuxtTypeScript() {
try {
const { setup } = require('@nuxt/typescript')
consola.info('Initializing typeScript support')
await setup(path.resolve(rootDir, 'tsconfig.json'), options)
consola.success('TypeScript support enabled')
} catch (e) {
if (e.code === 'MODULE_NOT_FOUND') {
return false
} else {
throw (e)
return await imports.nuxtTypescript()
} catch (error) {
if (error.code !== 'MODULE_NOT_FOUND') {
throw (error)
}
}
}
export async function detectTypeScript(rootDir, options = {}) {
// Check if tsconfig.json exists in project rootDir
const tsConfigPath = path.resolve(rootDir, 'tsconfig.json')
// Skip if tsconfig.json not exists
if (!await fs.exists(tsConfigPath)) {
return false
}
// Register runtime support
await registerTSNode(tsConfigPath, options)
// Try to load @nuxt/typescript
const nuxtTypeScript = await getNuxtTypeScript()
// If exists do additional setup
if (nuxtTypeScript) {
await nuxtTypeScript.setupDefaults(tsConfigPath)
}
return true
}

View File

@ -0,0 +1,41 @@
import { resolve } from 'path'
import { mkdirp, writeFile, remove } from 'fs-extra'
import { register } from 'ts-node'
import { detectTypeScript } from '../../src/utils/typescript'
jest.mock('ts-node')
describe('Typescript Support', () => {
const rootDir = 'tmp'
const rootDir2 = 'tmp2'
const tsConfigPath = resolve(rootDir, 'tsconfig.json')
beforeAll(async () => {
await mkdirp(rootDir)
await mkdirp(rootDir2)
await writeFile(tsConfigPath, '{}', 'utf-8')
})
test('detectTypeScript detects and registers runtime', async () => {
register.mockReset()
await detectTypeScript(rootDir)
expect(register).toHaveBeenCalledTimes(1)
expect(register).toHaveBeenCalledWith({
project: tsConfigPath,
compilerOptions: {
module: 'commonjs'
}
})
})
test('detectTypeScript skips rootDir without tsconfig.json', async () => {
register.mockReset()
await detectTypeScript(rootDir2)
expect(register).toHaveBeenCalledTimes(0)
})
afterAll(async () => {
await remove(rootDir)
await remove(rootDir2)
})
})

View File

@ -25,7 +25,6 @@
"fork-ts-checker-webpack-plugin": "^1.0.1",
"fs-extra": "^7.0.1",
"ts-loader": "^5.3.3",
"ts-node": "^8.0.3",
"typescript": "^3.4.1"
},
"publishConfig": {

View File

@ -1,5 +1,4 @@
import { existsSync, writeJSON } from 'fs-extra'
import { register } from 'ts-node'
import { exists, readFile, writeJSON } from 'fs-extra'
import consola from 'consola'
export const defaultTsJsonConfig = {
@ -35,26 +34,15 @@ export const defaultTsJsonConfig = {
}
}
let _setup = false
export async function setupDefaults(tsConfigPath) {
let contents = ''
export async function setup(tsConfigPath, options = {}) {
if (_setup) {
return
if (await exists(tsConfigPath)) {
contents = await readFile(tsConfigPath, 'utf-8')
}
_setup = true
// Only create a default `tsconfig.json` if it doesn't exist
if (!existsSync(tsConfigPath)) {
consola.info(`Generating tsconfig.json (${tsConfigPath})`)
if (!contents || contents === '{}') {
consola.info(`Generating ${tsConfigPath.replace(process.cwd(), '')}`)
await writeJSON(tsConfigPath, defaultTsJsonConfig, { spaces: 2 })
}
// https://github.com/TypeStrong/ts-node
register({
project: tsConfigPath,
compilerOptions: {
module: 'commonjs'
},
...options
})
}

View File

@ -1,39 +1,31 @@
import { resolve } from 'path'
import { mkdirp, readJSON, remove } from 'fs-extra'
import { register } from 'ts-node'
import { defaultTsJsonConfig, setup as setupTypeScript } from '@nuxt/typescript'
jest.mock('ts-node')
import { mkdirp, readJSON, writeFile, remove, readFile } from 'fs-extra'
import { defaultTsJsonConfig, setupDefaults } from '@nuxt/typescript'
describe('typescript setup', () => {
const rootDir = 'tmp'
const tsConfigPath = resolve(rootDir, 'tsconfig.json')
beforeAll(async () => {
// We're assuming that rootDir provided to setupTypeScript is existing so we create the tested one
await mkdirp(rootDir)
await setupTypeScript(tsConfigPath)
await writeFile(tsConfigPath, '{}', 'utf-8')
})
test('tsconfig.json has been created with defaults', async () => {
test('Create tsconfig.json with defaults', async () => {
await setupDefaults(tsConfigPath)
expect(await readJSON(tsConfigPath)).toEqual(defaultTsJsonConfig)
})
test('ts-node has been registered once', async () => {
// Call setupTypeScript a second time to test guard
await setupTypeScript(tsConfigPath)
test('Do not override tsconfig.json', async () => {
const fooJSON = '{ "foo": 123 }'
await writeFile(tsConfigPath, fooJSON, 'utf-8')
expect(register).toHaveBeenCalledTimes(1)
expect(register).toHaveBeenCalledWith({
project: tsConfigPath,
compilerOptions: {
module: 'commonjs'
}
})
await setupDefaults(tsConfigPath)
expect(await readFile(tsConfigPath, 'utf-8')).toEqual(fooJSON)
})
afterAll(async () => {
// Clean workspace by removing the temporary folder (and the generated tsconfig.json at the same time)
await remove(rootDir)
})
})