fix(ts): better tsconfig.json handling & improve tests (#4856)

* fix(ts): make ts-node register the right `tsconfig.json`

* setup guard & change require in nuxt-ts bin

* improve tests + test guard

* remove typescript-custom fixture

* Move TS unit test from `test/unit` to `packages/typescript/test`

* fix tests
This commit is contained in:
Kevin Marrec 2019-01-28 14:29:13 +01:00 committed by Pooya Parsa
parent 3d0bc199ed
commit f18ce4e5d4
14 changed files with 115 additions and 176 deletions

View File

@ -1,14 +1,17 @@
#!/usr/bin/env node
const { resolve } = require('path')
// Globally indicate we are running in ts mode
process.env.NUXT_TS = 'true'
const nuxtCommands = ['dev', 'build', 'generate', 'start']
const rootDir = (process.argv[2] && !nuxtCommands.includes(process.argv[2])) ? process.argv[2] : process.cwd()
const tsConfigPath = resolve(rootDir, 'tsconfig.json')
const suffix = require('../package.json').name.includes('-edge') ? '-edge' : ''
require('@nuxt/typescript' + suffix).setup(rootDir).then(() => {
require('@nuxt/typescript' + suffix).setup(tsConfigPath).then(() => {
require('@nuxt/cli' + suffix).run()
}).catch((error) => {
require('consola').fatal(error)

View File

@ -1,36 +0,0 @@
import { resolve } from 'path'
import { prompt } from 'enquirer'
import { existsSync, writeJSON } from 'fs-extra'
import chalk from 'chalk'
import consola from 'consola'
import env from 'std-env'
export async function generateTsConfigIfMissing(rootDir) {
const tsConfigPath = resolve(rootDir, 'tsconfig.json')
if (!existsSync(tsConfigPath)) {
const { confirmGeneration } = await prompt({
type: 'confirm',
name: 'confirmGeneration',
message: `Missing ${chalk.bold.blue('tsconfig.json')} in ${rootDir === process.cwd() ? 'current directory' : chalk.bold.green(resolve(rootDir))}, generate it ?`,
initial: true,
skip: env.minimal
})
if (confirmGeneration) {
const configToExtend = '@nuxt/typescript'
await writeJSON(tsConfigPath, {
extends: configToExtend,
compilerOptions: {
baseUrl: '.',
types: [
'@types/node',
'@nuxt/vue-app'
]
}
}, { spaces: 2 })
consola.info(`Extending ${chalk.bold.blue(`node_modules/${configToExtend}/tsconfig.json`)}`)
consola.success(`Generated successfully at ${chalk.bold.green(resolve(rootDir, 'tsconfig.json'))}`)
}
}
}

View File

@ -1,7 +1,49 @@
import { generateTsConfigIfMissing } from './config-generation'
import { registerTsNode } from './ts-node'
import chalk from 'chalk'
import consola from 'consola'
import env from 'std-env'
import { prompt } from 'enquirer'
import { existsSync, writeJSON } from 'fs-extra'
import { register } from 'ts-node'
export async function setup(rootDir) {
await generateTsConfigIfMissing(rootDir)
registerTsNode()
async function generateTsConfig(tsConfigPath) {
const configToExtend = '@nuxt/typescript'
await writeJSON(tsConfigPath, {
extends: configToExtend,
compilerOptions: {
baseUrl: '.',
types: [
'@types/node',
'@nuxt/vue-app'
]
}
}, { spaces: 2 })
consola.info(`Extending ${chalk.bold.blue(`node_modules/${configToExtend}/tsconfig.json`)}`)
consola.success(`Generated successfully at ${chalk.bold.green(tsConfigPath)}`)
}
let _setup = false
export async function setup(tsConfigPath) {
if (_setup) {
return
}
_setup = true
if (!existsSync(tsConfigPath)) {
const { confirmGeneration } = await prompt({
type: 'confirm',
name: 'confirmGeneration',
message: `${chalk.bold.blue(tsConfigPath)} is missing, generate it ?`,
initial: true,
skip: env.minimal
})
if (confirmGeneration) {
await generateTsConfig(tsConfigPath)
}
}
// https://github.com/TypeStrong/ts-node
register({
project: tsConfigPath
})
}

View File

@ -1,6 +0,0 @@
import { register } from 'ts-node'
export function registerTsNode() {
// https://github.com/TypeStrong/ts-node
register()
}

View File

@ -0,0 +1,46 @@
import { resolve } from 'path'
import { exists, mkdirp, readJSON, remove } from 'fs-extra'
import { register } from 'ts-node'
import { setup as setupTypeScript } from '@nuxt/typescript'
jest.mock('ts-node')
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)
})
test('tsconfig.json has been generated if missing', async () => {
expect(await exists(tsConfigPath)).toBe(true)
expect(await readJSON(tsConfigPath)).toEqual({
extends: '@nuxt/typescript',
compilerOptions: {
baseUrl: '.',
types: [
'@types/node',
'@nuxt/vue-app'
]
}
})
})
test('ts-node has been registered once', async () => {
// Call setupTypeScript a second time to test guard
await setupTypeScript(tsConfigPath)
expect(register).toHaveBeenCalledTimes(1)
expect(register).toHaveBeenCalledWith({
project: tsConfigPath
})
})
afterAll(async () => {
// Clean workspace by removing the temporary folder (and the generated tsconfig.json at the same time)
await remove(tsConfigPath)
})
})

View File

@ -1,10 +0,0 @@
<template>
<Nuxt />
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component
export default class DefaultLayout extends Vue {}
</script>

View File

@ -1,32 +0,0 @@
import path from 'path'
import consola from 'consola'
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'
export default function typeScriptModule() {
// Add .ts extension for store, middleware and more
this.nuxt.options.extensions.push('ts')
// Extend build
this.extendBuild((config, { isClient }) => {
// Add TypeScript loader
config.module.rules.push({
test: /\.ts$/,
loader: 'ts-loader',
options: {
transpileOnly: true,
appendTsSuffixTo: ['\\.vue$']
}
})
// Add .ts extension in webpack resolve
config.resolve.extensions.push('.ts')
if (isClient) {
config.plugins.push(new ForkTsCheckerWebpackPlugin({
vue: true,
tsconfig: path.resolve(this.options.srcDir, 'tsconfig.json'),
tslint: false,
logger: consola
}))
}
})
}

View File

@ -1,3 +0,0 @@
export default {
modules: ['~/modules/typescript']
}

View File

@ -1,8 +0,0 @@
import Vue from 'vue'
export default Vue.extend({
name: 'About',
render (h) {
return h('div', 'About Page')
}
})

View File

@ -1,12 +0,0 @@
<template>
<div>{{ message }}</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component
export default class Index extends Vue {
message: string = 'Index Page'
}
</script>

View File

@ -1,21 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"moduleResolution": "node",
"lib": ["esnext", "esnext.asynciterable", "dom"],
"esModuleInterop": true,
"experimentalDecorators": true,
"allowJs": true,
"sourceMap": true,
"strict": true,
"noImplicitAny": false,
"noEmit": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"baseUrl": ".",
"paths": {
"~/*": ["./*"]
}
}
}

View File

@ -1,3 +0,0 @@
import { buildFixture } from '../../utils/build'
buildFixture('typescript-custom')

View File

@ -1,27 +0,0 @@
import { loadFixture, getPort, Nuxt } from '../utils'
let nuxt = null
describe('typescript-custom', () => {
beforeAll(async () => {
const options = await loadFixture('typescript-custom')
nuxt = new Nuxt(options)
const port = await getPort()
await nuxt.server.listen(port, '0.0.0.0')
})
test('/', async () => {
const { html } = await nuxt.server.renderRoute('/')
expect(html).toContain('<div>Index Page</div>')
})
test('/about', async () => {
const { html } = await nuxt.server.renderRoute('/about')
expect(html).toContain('<div>About Page</div>')
})
// Close server and ask nuxt to stop listening to file changes
afterAll(async () => {
await nuxt.close()
})
})

View File

@ -7,17 +7,15 @@ jest.mock('ts-node')
describe('typescript setup', () => {
const rootDir = 'tmp'
const tsConfigPath = resolve(rootDir, 'tsconfig.json')
beforeAll(() => {
setupTypeScript(rootDir)
beforeAll(async () => {
// We're assuming that rootDir provided to setupTypeScript is existing so we create the tested one
await mkdirp(rootDir)
await setupTypeScript(tsConfigPath)
})
test('tsconfig.json has been generated if missing', async () => {
// We're assuming that rootDir provided to setupTypeScript is existing so we create the tested one
await mkdirp(rootDir)
const tsConfigPath = resolve(rootDir, 'tsconfig.json')
expect(await exists(tsConfigPath)).toBe(true)
expect(await readJSON(tsConfigPath)).toEqual({
extends: '@nuxt/typescript',
@ -29,12 +27,20 @@ describe('typescript setup', () => {
]
}
})
// Clean workspace by removing the temporary folder (and the generated tsconfig.json at the same time)
await remove(rootDir)
})
test('ts-node has been registered', () => {
expect(register).toHaveBeenCalled()
test('ts-node has been registered once', async () => {
// Call setupTypeScript a second time to test guard
await setupTypeScript(tsConfigPath)
expect(register).toHaveBeenCalledTimes(1)
expect(register).toHaveBeenCalledWith({
project: tsConfigPath
})
})
afterAll(async () => {
// Clean workspace by removing the temporary folder (and the generated tsconfig.json at the same time)
await remove(tsConfigPath)
})
})