refactor(ts): better DX for typescript support (#5079)

Breaking change : `build.useForkTsChecker` renamed to `build.typescript.typeCheck`
This commit is contained in:
Kevin Marrec 2019-03-14 11:07:47 +01:00 committed by Pooya Parsa
parent 821676511b
commit 920f444b6e
39 changed files with 299 additions and 257 deletions

View File

@ -9,6 +9,7 @@ coverage
## cofeescript ## cofeescript
examples/coffeescript/pages/index.vue examples/coffeescript/pages/index.vue
examples/pug-stylus-coffee/ examples/pug-stylus-coffee/
examples/typescript-eslint/
# Packages # Packages
# vue-app # vue-app

View File

@ -1,21 +1,8 @@
#!/usr/bin/env node #!/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' : '' const suffix = require('../package.json').name.includes('-edge') ? '-edge' : ''
require('@nuxt/cli' + suffix).run()
const errorHandler = (error) => { .catch((error) => {
require('consola').fatal(error) require('consola').fatal(error)
process.exit(2) process.exit(2)
} })
require('@nuxt/typescript' + suffix).setup(tsConfigPath).then(() => {
require('@nuxt/cli' + suffix).run().catch(errorHandler)
}).catch(errorHandler)

View File

@ -1,8 +1,8 @@
module.exports = { module.exports = {
apps: [ apps: [
{ {
name: 'pm2-nuxt-ts', name: 'pm2-nuxt-typescript',
script: './node_modules/.bin/nuxt-ts', script: './node_modules/.bin/nuxt',
args: 'start', args: 'start',
instances: 2, instances: 2,
exec_mode: 'cluster', exec_mode: 'cluster',

View File

@ -2,17 +2,16 @@
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"nuxt-ts": "latest", "nuxt": "latest",
"vue-property-decorator": "^7.3.0" "vue-property-decorator": "^7.3.0"
}, },
"scripts": { "scripts": {
"dev": "nuxt-ts", "dev": "nuxt",
"build": "nuxt-ts build", "build": "nuxt build",
"start": "nuxt-ts start", "start": "nuxt start",
"generate": "nuxt-ts generate", "generate": "nuxt generate"
"lint": "tslint --project ."
}, },
"devDependencies": { "devDependencies": {
"tslint-config-standard": "^8.0.1" "@nuxt/typescript": "latest"
} }
} }

View File

@ -1,10 +1 @@
{ {}
"extends": "@nuxt/typescript",
"compilerOptions": {
"baseUrl": ".",
"types": [
"@types/node",
"@nuxt/vue-app"
]
}
}

View File

@ -1,9 +0,0 @@
{
"defaultSeverity": "error",
"extends": [
"tslint-config-standard"
],
"rules": {
"prefer-const": true
}
}

View File

@ -0,0 +1,9 @@
module.exports = {
plugins: ['@typescript-eslint'],
parserOptions: {
parser: '@typescript-eslint/parser'
},
extends: [
'@nuxtjs'
]
}

15
examples/typescript-eslint/.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
# Dependencies
node_modules
# Logs
*.log*
# IDE
.idea
.vscode
# Nuxt build
.nuxt
# Nuxt generate
dist

View File

@ -0,0 +1,33 @@
# Nuxt with TypeScript & ESLint example
Use `yarn lint` or `npm run lint` to lint your TypeScript project !
## Why ESLint and not TSLint ?
See https://eslint.org/blog/2019/01/future-typescript-eslint
##
## VSCode settings
If you're using VSCode, we recommend using these settings :
```json
"eslint.autoFixOnSave": true,
"eslint.validate": [
{
"language": "javascript",
"autoFix": true
},
{
"language": "typescript",
"autoFix": true
},
{
"language": "vue",
"autoFix": true
}
]
```
It will lint your `.js`, `.ts` & `.vue` files whenever you're saving them.

View File

@ -0,0 +1 @@
export default {}

View File

@ -0,0 +1,30 @@
{
"version": "1.0.0",
"private": true,
"dependencies": {
"nuxt": "latest",
"vue-property-decorator": "^7.3.0"
},
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate",
"lint": "eslint --ext .ts,.js,.vue --ignore-path .gitignore .",
"lint:fix": "yarn lint --fix",
"post-update": "yarn upgrade --latest"
},
"devDependencies": {
"@nuxt/typescript": "latest",
"@nuxtjs/eslint-config": "latest",
"@typescript-eslint/eslint-plugin": "^1.4.2",
"eslint": "^5.14.1",
"eslint-config-standard": "^12.0.0",
"eslint-plugin-import": "^2.16.0",
"eslint-plugin-jest": "^22.3.0",
"eslint-plugin-node": "^8.0.1",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^5.2.2"
}
}

View File

@ -0,0 +1,14 @@
<template>
<div>
<h1>{{ title }}</h1>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component
export default class Home extends Vue {
title = 'TypeScript + ESLint example'
}
</script>

View File

@ -0,0 +1 @@
{}

View File

@ -3,20 +3,18 @@
"private": true, "private": true,
"version": "1.0.0", "version": "1.0.0",
"scripts": { "scripts": {
"dev": "nuxt-ts", "dev": "nuxt",
"build": "nuxt-ts build", "build": "nuxt build",
"start": "nuxt-ts start", "start": "nuxt start",
"generate": "nuxt-ts generate", "generate": "nuxt generate",
"lint": "tslint --project .",
"lint:fix": "tslint --project . --fix",
"post-update": "yarn upgrade --latest", "post-update": "yarn upgrade --latest",
"watch:css": "tcm components -w" "watch:css": "tcm components -w"
}, },
"dependencies": { "dependencies": {
"nuxt-ts": "latest" "nuxt": "latest"
}, },
"devDependencies": { "devDependencies": {
"tslint-config-standard": "^8.0.1", "@nuxt/typescript": "latest",
"typed-css-modules": "^0.3.7" "typed-css-modules": "^0.3.7"
} }
} }

View File

@ -1,8 +1,6 @@
{ {
"extends": "@nuxt/typescript",
"compilerOptions": { "compilerOptions": {
"baseUrl": ".", "jsx": "preserve",
"noImplicitThis": true, "noImplicitThis": true
"types": ["@types/node", "@nuxt/vue-app"]
} }
} }

View File

@ -1,7 +0,0 @@
{
"defaultSeverity": "error",
"extends": ["tslint-config-standard"],
"rules": {
"prefer-const": true
}
}

View File

@ -3,20 +3,19 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"axios": "^0.18.0", "axios": "^0.18.0",
"nuxt-ts": "latest", "nuxt": "latest",
"tachyons": "^4.11.1", "tachyons": "^4.11.1",
"vue-property-decorator": "^7.3.0", "vue-property-decorator": "^7.3.0",
"vuex-class": "^0.3.1" "vuex-class": "^0.3.1"
}, },
"scripts": { "scripts": {
"dev": "nuxt-ts", "dev": "nuxt",
"build": "nuxt-ts build", "build": "nuxt build",
"start": "nuxt-ts start", "start": "nuxt start",
"generate": "nuxt-ts generate", "generate": "nuxt generate",
"lint": "tslint --project .",
"post-update": "yarn upgrade --latest" "post-update": "yarn upgrade --latest"
}, },
"devDependencies": { "devDependencies": {
"tslint-config-standard": "^8.0.1" "@nuxt/typescript": "latest"
} }
} }

View File

@ -1,11 +1 @@
{ {}
"extends": "@nuxt/typescript",
"compilerOptions": {
"baseUrl": ".",
"noImplicitAny": false,
"types": [
"@types/node",
"@nuxt/vue-app"
]
}
}

View File

@ -1,9 +0,0 @@
{
"defaultSeverity": "error",
"extends": [
"tslint-config-standard"
],
"rules": {
"prefer-const": true
}
}

View File

@ -2,18 +2,17 @@
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"nuxt-ts": "latest", "nuxt": "latest",
"vue-property-decorator": "^7.3.0" "vue-property-decorator": "^7.3.0"
}, },
"scripts": { "scripts": {
"dev": "nuxt-ts", "dev": "nuxt",
"build": "nuxt-ts build", "build": "nuxt build",
"start": "nuxt-ts start", "start": "nuxt start",
"generate": "nuxt-ts generate", "generate": "nuxt generate",
"lint": "tslint --project .",
"post-update": "yarn upgrade --latest" "post-update": "yarn upgrade --latest"
}, },
"devDependencies": { "devDependencies": {
"tslint-config-standard": "^8.0.1" "@nuxt/typescript": "latest"
} }
} }

View File

@ -1,10 +1 @@
{ {}
"extends": "@nuxt/typescript",
"compilerOptions": {
"baseUrl": ".",
"types": [
"@types/node",
"@nuxt/vue-app"
]
}
}

View File

@ -1,9 +0,0 @@
{
"defaultSeverity": "error",
"extends": [
"tslint-config-standard"
],
"rules": {
"prefer-const": true
}
}

View File

@ -1,9 +1,12 @@
import path from 'path'
import consola from 'consola' import consola from 'consola'
import minimist from 'minimist' import minimist from 'minimist'
import { name, version } from '../package.json' import { name, version } from '../package.json'
import { loadNuxtConfig, forceExit } from './utils' import { loadNuxtConfig, forceExit } from './utils'
import { indent, foldLines, colorize } from './utils/formatting' import { indent, foldLines, colorize } from './utils/formatting'
import { startSpaces, optionSpaces, forceExitTimeout } from './utils/constants' import { startSpaces, optionSpaces, forceExitTimeout } from './utils/constants'
import { detectAndSetupTypeScriptSupport } from './utils/typescript'
import * as imports from './imports' import * as imports from './imports'
export default class NuxtCommand { export default class NuxtCommand {
@ -73,7 +76,10 @@ export default class NuxtCommand {
return this._parsedArgv return this._parsedArgv
} }
async getNuxtConfig(extraOptions) { async getNuxtConfig(extraOptions = {}) {
const rootDir = path.resolve(this.argv._[0] || '.')
extraOptions._typescript = await detectAndSetupTypeScriptSupport(rootDir, { transpileOnly: this.cmd.name === 'start' })
const config = await loadNuxtConfig(this.argv) const config = await loadNuxtConfig(this.argv)
const options = Object.assign(config, extraOptions) const options = Object.assign(config, extraOptions)

View File

@ -1,5 +1,4 @@
import path from 'path' import path from 'path'
import { existsSync } from 'fs'
import consola from 'consola' import consola from 'consola'
import esm from 'esm' import esm from 'esm'
import exit from 'exit' import exit from 'exit'
@ -11,14 +10,14 @@ import prettyBytes from 'pretty-bytes'
import env from 'std-env' import env from 'std-env'
import { successBox, warningBox } from './formatting' import { successBox, warningBox } from './formatting'
export const requireModule = process.env.NUXT_TS ? require : esm(module, { const esmOptions = {
cache: false, cache: false,
cjs: { cjs: {
cache: true, cache: true,
vars: true, vars: true,
namedExports: true namedExports: true
} }
}) }
export const eventsMapping = { export const eventsMapping = {
add: { icon: '+', color: 'green', action: 'Created' }, add: { icon: '+', color: 'green', action: 'Created' },
@ -26,18 +25,23 @@ export const eventsMapping = {
unlink: { icon: '-', color: 'red', action: 'Removed' } unlink: { icon: '-', color: 'red', action: 'Removed' }
} }
const getRootDir = argv => path.resolve(argv._[0] || '.')
const getNuxtConfigFile = argv => path.resolve(getRootDir(argv), argv['config-file'])
export async function loadNuxtConfig(argv) { export async function loadNuxtConfig(argv) {
const rootDir = getRootDir(argv) const rootDir = path.resolve(argv._[0] || '.')
const nuxtConfigFile = getNuxtConfigFile(argv) let nuxtConfigFile
let options = {} let options = {}
if (existsSync(nuxtConfigFile)) { try {
delete require.cache[nuxtConfigFile] nuxtConfigFile = require.resolve(path.resolve(rootDir, argv['config-file']))
options = requireModule(nuxtConfigFile) || {} } catch (e) {
if (e.code !== 'MODULE_NOT_FOUND') {
throw (e)
} else if (argv['config-file'] !== defaultNuxtConfigFile) {
consola.fatal('Could not load config file: ' + argv['config-file'])
}
}
if (nuxtConfigFile) {
options = (nuxtConfigFile.endsWith('.ts') ? require(nuxtConfigFile) : esm(module, esmOptions)(nuxtConfigFile)) || {}
if (options.default) { if (options.default) {
options = options.default options = options.default
} }
@ -56,9 +60,8 @@ export async function loadNuxtConfig(argv) {
// Keep _nuxtConfigFile for watching // Keep _nuxtConfigFile for watching
options._nuxtConfigFile = nuxtConfigFile options._nuxtConfigFile = nuxtConfigFile
} else if (argv['config-file'] !== defaultNuxtConfigFile) {
consola.fatal('Could not load config file: ' + argv['config-file'])
} }
if (typeof options.rootDir !== 'string') { if (typeof options.rootDir !== 'string') {
options.rootDir = rootDir options.rootDir = rootDir
} }

View File

@ -0,0 +1,38 @@
import path from 'path'
import { existsSync } from 'fs'
import chalk from 'chalk'
import consola from 'consola'
import { warningBox } from './formatting'
const dependencyNotFoundMessage =
`Please install @nuxt/typescript and rerun the command
${chalk.bold('Using yarn')}
yarn add -D @nuxt/typescript
${chalk.bold('Using npm')}
npm install -D @nuxt/typescript`
export async function detectAndSetupTypeScriptSupport(rootDir, options = {}) {
const tsConfigPath = path.resolve(rootDir, 'tsconfig.json')
if (!existsSync(tsConfigPath)) {
return false
}
consola.info(`${chalk.bold.blue('tsconfig.json')} found, enabling TypeScript runtime support`)
try {
const { setup } = require('@nuxt/typescript')
await setup(tsConfigPath, options)
} catch (e) {
if (e.code === 'MODULE_NOT_FOUND') {
process.stdout.write(warningBox(dependencyNotFoundMessage, chalk.yellow('An external official dependency is needed to enable TS support')))
process.exit(1)
} else {
throw (e)
}
}
return true
}

View File

@ -14,7 +14,7 @@ exports[`cli/command builds help text 1`] = `
--universal, -u Launch in Universal --universal, -u Launch in Universal
mode (default) mode (default)
--config-file, -c Path to Nuxt.js --config-file, -c Path to Nuxt.js
config file (default: nuxt.config.js) config file (default: nuxt.config)
--modern, -m Build/Start app for --modern, -m Build/Start app for
modern browsers, e.g. server, client and modern browsers, e.g. server, client and
false false

View File

@ -54,7 +54,9 @@ export default () => ({
}, },
vueStyle: {} vueStyle: {}
}, },
useForkTsChecker: process.env.NUXT_TS === 'true', typescript: {
typeCheck: true
},
styleResources: {}, styleResources: {},
plugins: [], plugins: [],
terser: {}, terser: {},

View File

@ -10,7 +10,7 @@ import router from './router'
import server from './server' import server from './server'
import cli from './cli' import cli from './cli'
export const defaultNuxtConfigFile = `nuxt.config${process.env.NUXT_TS === 'true' ? '.ts' : '.js'}` export const defaultNuxtConfigFile = 'nuxt.config'
export function getDefaultNuxtConfig(options = {}) { export function getDefaultNuxtConfig(options = {}) {
if (!options.env) { if (!options.env) {

View File

@ -84,7 +84,7 @@ export function getNuxtConfig(_options) {
// Default value for _nuxtConfigFile // Default value for _nuxtConfigFile
if (!options._nuxtConfigFile) { if (!options._nuxtConfigFile) {
options._nuxtConfigFile = path.resolve(options.rootDir, defaultNuxtConfigFile) options._nuxtConfigFile = path.resolve(options.rootDir, `${defaultNuxtConfigFile}.js`)
} }
// Watch for _nuxtConfigFile changes // Watch for _nuxtConfigFile changes

View File

@ -131,7 +131,9 @@ Object {
"templates": Array [], "templates": Array [],
"terser": Object {}, "terser": Object {},
"transpile": Array [], "transpile": Array [],
"useForkTsChecker": false, "typescript": Object {
"typeCheck": true,
},
"watch": Array [], "watch": Array [],
}, },
"buildDir": "/var/nuxt/test/.nuxt", "buildDir": "/var/nuxt/test/.nuxt",

View File

@ -121,7 +121,9 @@ Object {
"templates": Array [], "templates": Array [],
"terser": Object {}, "terser": Object {},
"transpile": Array [], "transpile": Array [],
"useForkTsChecker": false, "typescript": Object {
"typeCheck": true,
},
"watch": Array [], "watch": Array [],
}, },
"buildDir": ".nuxt", "buildDir": ".nuxt",
@ -450,7 +452,9 @@ Object {
"templates": Array [], "templates": Array [],
"terser": Object {}, "terser": Object {},
"transpile": Array [], "transpile": Array [],
"useForkTsChecker": false, "typescript": Object {
"typeCheck": true,
},
"watch": Array [], "watch": Array [],
}, },
"buildDir": ".nuxt", "buildDir": ".nuxt",

View File

@ -4,8 +4,7 @@
"repository": "nuxt/nuxt.js", "repository": "nuxt/nuxt.js",
"license": "MIT", "license": "MIT",
"files": [ "files": [
"dist", "dist"
"tsconfig.json"
], ],
"main": "dist/typescript.js", "main": "dist/typescript.js",
"dependencies": { "dependencies": {
@ -22,15 +21,11 @@
"@types/webpack-bundle-analyzer": "^2.13.1", "@types/webpack-bundle-analyzer": "^2.13.1",
"@types/webpack-dev-middleware": "^2.0.2", "@types/webpack-dev-middleware": "^2.0.2",
"@types/webpack-hot-middleware": "^2.16.5", "@types/webpack-hot-middleware": "^2.16.5",
"chalk": "^2.4.2",
"consola": "^2.5.6",
"enquirer": "^2.3.0",
"fork-ts-checker-webpack-plugin": "^1.0.0", "fork-ts-checker-webpack-plugin": "^1.0.0",
"fs-extra": "^7.0.1", "fs-extra": "^7.0.1",
"std-env": "^2.2.1", "lodash": "^4.17.11",
"ts-loader": "^5.3.3", "ts-loader": "^5.3.3",
"ts-node": "^8.0.3", "ts-node": "^8.0.3",
"tslint": "^5.14.0",
"typescript": "^3.3.3333" "typescript": "^3.3.3333"
}, },
"publishConfig": { "publishConfig": {

View File

@ -1,53 +1,57 @@
import chalk from 'chalk' import { readJSON, writeJSON } from 'fs-extra'
import consola from 'consola'
import env from 'std-env'
import { prompt } from 'enquirer'
import { existsSync, writeJSON } from 'fs-extra'
import { register } from 'ts-node' import { register } from 'ts-node'
import defaultsDeep from 'lodash/defaultsDeep'
async function generateTsConfig(tsConfigPath) { export const defaultTsJsonConfig = {
const configToExtend = '@nuxt/typescript'
await writeJSON(tsConfigPath, {
extends: configToExtend,
compilerOptions: { compilerOptions: {
target: 'esnext',
module: 'esnext',
moduleResolution: 'node',
lib: [
'esnext',
'esnext.asynciterable',
'dom'
],
esModuleInterop: true,
experimentalDecorators: true,
allowJs: true,
sourceMap: true,
strict: true,
noImplicitAny: false,
noEmit: true,
baseUrl: '.', baseUrl: '.',
paths: {
'~/*': [
'./*'
],
'@/*': [
'./*'
]
},
types: [ types: [
'@types/node', '@types/node',
'@nuxt/vue-app' '@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 let _setup = false
export async function setup(tsConfigPath) { export async function setup(tsConfigPath, options = {}) {
if (_setup) { if (_setup) {
return return
} }
_setup = true _setup = true
if (!existsSync(tsConfigPath)) { const config = await readJSON(tsConfigPath)
const { confirmGeneration } = await prompt({ await writeJSON(tsConfigPath, defaultsDeep(config, defaultTsJsonConfig), { spaces: 2 })
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 // https://github.com/TypeStrong/ts-node
register({ register({
project: tsConfigPath, project: tsConfigPath,
compilerOptions: { compilerOptions: {
module: 'commonjs' module: 'commonjs'
}, },
transpileOnly: process.argv[2] === 'start' ...options
}) })
} }

View File

@ -1,12 +1,9 @@
import { resolve } from 'path' import { resolve } from 'path'
import { exists, mkdirp, readJSON, remove } from 'fs-extra' import { mkdirp, readJSON, remove, writeJSON } from 'fs-extra'
import { register } from 'ts-node' import { register } from 'ts-node'
import { setup as setupTypeScript } from '@nuxt/typescript' import { defaultTsJsonConfig, setup as setupTypeScript } from '@nuxt/typescript'
jest.mock('ts-node') jest.mock('ts-node')
jest.mock('enquirer', () => ({
prompt: jest.fn(() => ({ confirmGeneration: true }))
}))
describe('typescript setup', () => { describe('typescript setup', () => {
const rootDir = 'tmp' const rootDir = 'tmp'
@ -15,21 +12,12 @@ describe('typescript setup', () => {
beforeAll(async () => { beforeAll(async () => {
// We're assuming that rootDir provided to setupTypeScript is existing so we create the tested one // We're assuming that rootDir provided to setupTypeScript is existing so we create the tested one
await mkdirp(rootDir) await mkdirp(rootDir)
await writeJSON(tsConfigPath, {})
await setupTypeScript(tsConfigPath) await setupTypeScript(tsConfigPath)
}) })
test('tsconfig.json has been generated if missing', async () => { test('tsconfig.json has been updated with defaults', async () => {
expect(await exists(tsConfigPath)).toBe(true) expect(await readJSON(tsConfigPath)).toEqual(defaultTsJsonConfig)
expect(await readJSON(tsConfigPath)).toEqual({
extends: '@nuxt/typescript',
compilerOptions: {
baseUrl: '.',
types: [
'@types/node',
'@nuxt/vue-app'
]
}
})
}) })
test('ts-node has been registered once', async () => { test('ts-node has been registered once', async () => {
@ -41,13 +29,12 @@ describe('typescript setup', () => {
project: tsConfigPath, project: tsConfigPath,
compilerOptions: { compilerOptions: {
module: 'commonjs' module: 'commonjs'
}, }
transpileOnly: false
}) })
}) })
afterAll(async () => { afterAll(async () => {
// Clean workspace by removing the temporary folder (and the generated tsconfig.json at the same time) // Clean workspace by removing the temporary folder (and the generated tsconfig.json at the same time)
await remove(tsConfigPath) await remove(rootDir)
}) })
}) })

View File

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

View File

@ -1,5 +1,4 @@
import path from 'path' import path from 'path'
import fs from 'fs'
import querystring from 'querystring' import querystring from 'querystring'
import consola from 'consola' import consola from 'consola'
import webpack from 'webpack' import webpack from 'webpack'
@ -77,7 +76,7 @@ export default class WebpackClientConfig extends WebpackBaseConfig {
plugins() { plugins() {
const plugins = super.plugins() const plugins = super.plugins()
const { buildOptions, options: { appTemplatePath, buildDir, rootDir, modern } } = this.buildContext const { buildOptions, options: { appTemplatePath, buildDir, modern, rootDir, _typescript } } = this.buildContext
// Generate output HTML for SSR // Generate output HTML for SSR
if (buildOptions.ssr) { if (buildOptions.ssr) {
@ -140,21 +139,16 @@ export default class WebpackClientConfig extends WebpackBaseConfig {
// TypeScript type checker // TypeScript type checker
// Only performs once per client compilation and only if `ts-loader` checker is not used (transpileOnly: true) // Only performs once per client compilation and only if `ts-loader` checker is not used (transpileOnly: true)
if (!this.isModern && this.loaders.ts.transpileOnly && buildOptions.useForkTsChecker) { if (_typescript && buildOptions.typescript && buildOptions.typescript.typeCheck && !this.isModern && this.loaders.ts.transpileOnly) {
const forkTsCheckerResolvedPath = this.buildContext.nuxt.resolver.resolveModule('fork-ts-checker-webpack-plugin') // We assume that "_typescript" being truthy means @nuxt/typescript is installed <=> fork-ts-checker-webpack-plugin is installed
if (forkTsCheckerResolvedPath) { const ForkTsCheckerWebpackPlugin = require(this.buildContext.nuxt.resolver.resolveModule('fork-ts-checker-webpack-plugin'))
const ForkTsCheckerWebpackPlugin = require(forkTsCheckerResolvedPath)
plugins.push(new ForkTsCheckerWebpackPlugin(Object.assign({ plugins.push(new ForkTsCheckerWebpackPlugin(Object.assign({
vue: true, vue: true,
tsconfig: path.resolve(rootDir, 'tsconfig.json'), tsconfig: path.resolve(rootDir, 'tsconfig.json'),
// https://github.com/Realytics/fork-ts-checker-webpack-plugin#options - tslint: boolean | string - So we set it false if file not found tslint: false, // We recommend using ESLint so we set this option to `false` by default
tslint: (tslintPath => fs.existsSync(tslintPath) && tslintPath)(path.resolve(rootDir, 'tslint.json')),
formatter: 'codeframe', formatter: 'codeframe',
logger: consola logger: consola
}, buildOptions.useForkTsChecker))) }, buildOptions.typescript.typeCheck)))
} else {
consola.warn('You need to install `fork-ts-checker-webpack-plugin` as devDependency to enable TypeScript type checking !')
}
} }
return plugins return plugins

View File

@ -1,8 +1,30 @@
{ {
"extends": "@nuxt/typescript",
"compilerOptions": { "compilerOptions": {
"baseUrl": ".", "target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"lib": [
"esnext",
"esnext.asynciterable",
"dom"
],
"esModuleInterop": true,
"experimentalDecorators": true,
"allowJs": true,
"jsx": "preserve",
"sourceMap": true,
"strict": true,
"noImplicitAny": false, "noImplicitAny": false,
"noEmit": true,
"baseUrl": ".",
"paths": {
"~/*": [
"./*"
],
"@/*": [
"./*"
]
},
"types": [ "types": [
"@types/node", "@types/node",
"@nuxt/vue-app" "@nuxt/vue-app"

View File

@ -8,7 +8,7 @@ describe('typescript modern', () => {
beforeAll(async () => { beforeAll(async () => {
const options = await loadFixture('typescript') const options = await loadFixture('typescript')
nuxt = new Nuxt(Object.assign(options, { modern: true, build: { useForkTsChecker: true } })) nuxt = new Nuxt(Object.assign(options, { modern: true, _typescript: true }))
await new Builder(nuxt, BundleBuilder).build() await new Builder(nuxt, BundleBuilder).build()
}) })

View File

@ -2184,7 +2184,7 @@ ansi-align@^3.0.0:
dependencies: dependencies:
string-width "^3.0.0" string-width "^3.0.0"
ansi-colors@^3.0.0, ansi-colors@^3.2.1: ansi-colors@^3.0.0:
version "3.2.4" version "3.2.4"
resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==
@ -4284,13 +4284,6 @@ enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0:
memory-fs "^0.4.0" memory-fs "^0.4.0"
tapable "^1.0.0" tapable "^1.0.0"
enquirer@^2.3.0:
version "2.3.0"
resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.0.tgz#c362c9d84984ebe854def63caaf12983a16af552"
integrity sha512-RNGUbRVlfnjmpxV+Ed+7CGu0rg3MK7MmlW+DW0v7V2zdAUBC1s4BxCRiIAozbYB2UJ+q4D+8tW9UFb11kF72/g==
dependencies:
ansi-colors "^3.2.1"
entities@^1.1.1, entities@~1.1.1: entities@^1.1.1, entities@~1.1.1:
version "1.1.2" version "1.1.2"
resolved "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" resolved "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"