mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-13 09:33:54 +00:00
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:
parent
3d0bc199ed
commit
f18ce4e5d4
@ -1,14 +1,17 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const { resolve } = require('path')
|
||||||
|
|
||||||
// Globally indicate we are running in ts mode
|
// Globally indicate we are running in ts mode
|
||||||
process.env.NUXT_TS = 'true'
|
process.env.NUXT_TS = 'true'
|
||||||
|
|
||||||
const nuxtCommands = ['dev', 'build', 'generate', 'start']
|
const nuxtCommands = ['dev', 'build', 'generate', 'start']
|
||||||
const rootDir = (process.argv[2] && !nuxtCommands.includes(process.argv[2])) ? process.argv[2] : process.cwd()
|
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' : ''
|
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()
|
require('@nuxt/cli' + suffix).run()
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
require('consola').fatal(error)
|
require('consola').fatal(error)
|
||||||
|
@ -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'))}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,49 @@
|
|||||||
import { generateTsConfigIfMissing } from './config-generation'
|
import chalk from 'chalk'
|
||||||
import { registerTsNode } from './ts-node'
|
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) {
|
async function generateTsConfig(tsConfigPath) {
|
||||||
await generateTsConfigIfMissing(rootDir)
|
const configToExtend = '@nuxt/typescript'
|
||||||
registerTsNode()
|
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
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
import { register } from 'ts-node'
|
|
||||||
|
|
||||||
export function registerTsNode() {
|
|
||||||
// https://github.com/TypeStrong/ts-node
|
|
||||||
register()
|
|
||||||
}
|
|
46
packages/typescript/test/setup.test.js
Normal file
46
packages/typescript/test/setup.test.js
Normal 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)
|
||||||
|
})
|
||||||
|
})
|
@ -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>
|
|
@ -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
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
export default {
|
|
||||||
modules: ['~/modules/typescript']
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
|
|
||||||
export default Vue.extend({
|
|
||||||
name: 'About',
|
|
||||||
render (h) {
|
|
||||||
return h('div', 'About Page')
|
|
||||||
}
|
|
||||||
})
|
|
12
test/fixtures/typescript-custom/pages/index.vue
vendored
12
test/fixtures/typescript-custom/pages/index.vue
vendored
@ -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>
|
|
21
test/fixtures/typescript-custom/tsconfig.json
vendored
21
test/fixtures/typescript-custom/tsconfig.json
vendored
@ -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": {
|
|
||||||
"~/*": ["./*"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
import { buildFixture } from '../../utils/build'
|
|
||||||
|
|
||||||
buildFixture('typescript-custom')
|
|
@ -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()
|
|
||||||
})
|
|
||||||
})
|
|
@ -7,17 +7,15 @@ jest.mock('ts-node')
|
|||||||
|
|
||||||
describe('typescript setup', () => {
|
describe('typescript setup', () => {
|
||||||
const rootDir = 'tmp'
|
const rootDir = 'tmp'
|
||||||
|
const tsConfigPath = resolve(rootDir, 'tsconfig.json')
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(async () => {
|
||||||
setupTypeScript(rootDir)
|
// 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 () => {
|
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 exists(tsConfigPath)).toBe(true)
|
||||||
expect(await readJSON(tsConfigPath)).toEqual({
|
expect(await readJSON(tsConfigPath)).toEqual({
|
||||||
extends: '@nuxt/typescript',
|
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', () => {
|
test('ts-node has been registered once', async () => {
|
||||||
expect(register).toHaveBeenCalled()
|
// 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)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user