From 920f444b6eb840b0f8a697539d4afa45c0b9abea Mon Sep 17 00:00:00 2001 From: Kevin Marrec Date: Thu, 14 Mar 2019 11:07:47 +0100 Subject: [PATCH] refactor(ts): better DX for typescript support (#5079) Breaking change : `build.useForkTsChecker` renamed to `build.typescript.typeCheck` --- .eslintignore | 1 + distributions/nuxt-ts/bin/nuxt-ts.js | 23 ++----- examples/pm2-typescript/ecosystem.config.js | 4 +- examples/pm2-typescript/package.json | 13 ++-- examples/pm2-typescript/tsconfig.json | 11 +-- examples/pm2-typescript/tslint.json | 9 --- examples/typescript-eslint/.eslintrc.js | 9 +++ examples/typescript-eslint/.gitignore | 15 ++++ examples/typescript-eslint/README.md | 33 +++++++++ examples/typescript-eslint/nuxt.config.ts | 1 + examples/typescript-eslint/package.json | 30 ++++++++ examples/typescript-eslint/pages/index.vue | 14 ++++ examples/typescript-eslint/tsconfig.json | 1 + examples/typescript-tsx/package.json | 14 ++-- examples/typescript-tsx/tsconfig.json | 6 +- examples/typescript-tsx/tslint.json | 7 -- examples/typescript-vuex/package.json | 13 ++-- examples/typescript-vuex/tsconfig.json | 12 +--- examples/typescript-vuex/tslint.json | 9 --- examples/typescript/package.json | 13 ++-- examples/typescript/tsconfig.json | 11 +-- examples/typescript/tslint.json | 9 --- packages/cli/src/command.js | 8 ++- packages/cli/src/utils/index.js | 31 +++++---- packages/cli/src/utils/typescript.js | 38 +++++++++++ .../unit/__snapshots__/command.test.js.snap | 2 +- packages/config/src/config/build.js | 4 +- packages/config/src/config/index.js | 2 +- packages/config/src/options.js | 2 +- .../test/__snapshots__/options.test.js.snap | 4 +- .../config/__snapshots__/index.test.js.snap | 8 ++- packages/typescript/package.json | 9 +-- packages/typescript/src/index.js | 68 ++++++++++--------- packages/typescript/test/setup.test.js | 27 ++------ packages/typescript/tsconfig.json | 30 -------- packages/webpack/src/config/client.js | 28 +++----- test/fixtures/typescript/tsconfig.json | 26 ++++++- test/unit/typescript.modern.test.js | 2 +- yarn.lock | 9 +-- 39 files changed, 299 insertions(+), 257 deletions(-) delete mode 100644 examples/pm2-typescript/tslint.json create mode 100644 examples/typescript-eslint/.eslintrc.js create mode 100644 examples/typescript-eslint/.gitignore create mode 100644 examples/typescript-eslint/README.md create mode 100644 examples/typescript-eslint/nuxt.config.ts create mode 100644 examples/typescript-eslint/package.json create mode 100644 examples/typescript-eslint/pages/index.vue create mode 100644 examples/typescript-eslint/tsconfig.json delete mode 100644 examples/typescript-tsx/tslint.json delete mode 100644 examples/typescript-vuex/tslint.json delete mode 100644 examples/typescript/tslint.json create mode 100644 packages/cli/src/utils/typescript.js delete mode 100644 packages/typescript/tsconfig.json diff --git a/.eslintignore b/.eslintignore index 8e3846f0c8..a3837325b1 100644 --- a/.eslintignore +++ b/.eslintignore @@ -9,6 +9,7 @@ coverage ## cofeescript examples/coffeescript/pages/index.vue examples/pug-stylus-coffee/ +examples/typescript-eslint/ # Packages # vue-app diff --git a/distributions/nuxt-ts/bin/nuxt-ts.js b/distributions/nuxt-ts/bin/nuxt-ts.js index 59d6ce03c5..25ea739baf 100755 --- a/distributions/nuxt-ts/bin/nuxt-ts.js +++ b/distributions/nuxt-ts/bin/nuxt-ts.js @@ -1,21 +1,8 @@ #!/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 errorHandler = (error) => { - require('consola').fatal(error) - process.exit(2) -} - -require('@nuxt/typescript' + suffix).setup(tsConfigPath).then(() => { - require('@nuxt/cli' + suffix).run().catch(errorHandler) -}).catch(errorHandler) +require('@nuxt/cli' + suffix).run() + .catch((error) => { + require('consola').fatal(error) + process.exit(2) + }) diff --git a/examples/pm2-typescript/ecosystem.config.js b/examples/pm2-typescript/ecosystem.config.js index 12f957ed7d..a3fbabbfd4 100644 --- a/examples/pm2-typescript/ecosystem.config.js +++ b/examples/pm2-typescript/ecosystem.config.js @@ -1,8 +1,8 @@ module.exports = { apps: [ { - name: 'pm2-nuxt-ts', - script: './node_modules/.bin/nuxt-ts', + name: 'pm2-nuxt-typescript', + script: './node_modules/.bin/nuxt', args: 'start', instances: 2, exec_mode: 'cluster', diff --git a/examples/pm2-typescript/package.json b/examples/pm2-typescript/package.json index c087e4795d..5c0788d7b5 100644 --- a/examples/pm2-typescript/package.json +++ b/examples/pm2-typescript/package.json @@ -2,17 +2,16 @@ "version": "1.0.0", "private": true, "dependencies": { - "nuxt-ts": "latest", + "nuxt": "latest", "vue-property-decorator": "^7.3.0" }, "scripts": { - "dev": "nuxt-ts", - "build": "nuxt-ts build", - "start": "nuxt-ts start", - "generate": "nuxt-ts generate", - "lint": "tslint --project ." + "dev": "nuxt", + "build": "nuxt build", + "start": "nuxt start", + "generate": "nuxt generate" }, "devDependencies": { - "tslint-config-standard": "^8.0.1" + "@nuxt/typescript": "latest" } } diff --git a/examples/pm2-typescript/tsconfig.json b/examples/pm2-typescript/tsconfig.json index e088a2e41c..0967ef424b 100644 --- a/examples/pm2-typescript/tsconfig.json +++ b/examples/pm2-typescript/tsconfig.json @@ -1,10 +1 @@ -{ - "extends": "@nuxt/typescript", - "compilerOptions": { - "baseUrl": ".", - "types": [ - "@types/node", - "@nuxt/vue-app" - ] - } -} +{} diff --git a/examples/pm2-typescript/tslint.json b/examples/pm2-typescript/tslint.json deleted file mode 100644 index 085d45bd4b..0000000000 --- a/examples/pm2-typescript/tslint.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "defaultSeverity": "error", - "extends": [ - "tslint-config-standard" - ], - "rules": { - "prefer-const": true - } -} diff --git a/examples/typescript-eslint/.eslintrc.js b/examples/typescript-eslint/.eslintrc.js new file mode 100644 index 0000000000..f4d35c167d --- /dev/null +++ b/examples/typescript-eslint/.eslintrc.js @@ -0,0 +1,9 @@ +module.exports = { + plugins: ['@typescript-eslint'], + parserOptions: { + parser: '@typescript-eslint/parser' + }, + extends: [ + '@nuxtjs' + ] +} diff --git a/examples/typescript-eslint/.gitignore b/examples/typescript-eslint/.gitignore new file mode 100644 index 0000000000..283de77f4b --- /dev/null +++ b/examples/typescript-eslint/.gitignore @@ -0,0 +1,15 @@ +# Dependencies +node_modules + +# Logs +*.log* + +# IDE +.idea +.vscode + +# Nuxt build +.nuxt + +# Nuxt generate +dist diff --git a/examples/typescript-eslint/README.md b/examples/typescript-eslint/README.md new file mode 100644 index 0000000000..b30cfcfcf5 --- /dev/null +++ b/examples/typescript-eslint/README.md @@ -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. diff --git a/examples/typescript-eslint/nuxt.config.ts b/examples/typescript-eslint/nuxt.config.ts new file mode 100644 index 0000000000..b1c6ea436a --- /dev/null +++ b/examples/typescript-eslint/nuxt.config.ts @@ -0,0 +1 @@ +export default {} diff --git a/examples/typescript-eslint/package.json b/examples/typescript-eslint/package.json new file mode 100644 index 0000000000..939f60d7ae --- /dev/null +++ b/examples/typescript-eslint/package.json @@ -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" + } +} diff --git a/examples/typescript-eslint/pages/index.vue b/examples/typescript-eslint/pages/index.vue new file mode 100644 index 0000000000..730e10426b --- /dev/null +++ b/examples/typescript-eslint/pages/index.vue @@ -0,0 +1,14 @@ + + + diff --git a/examples/typescript-eslint/tsconfig.json b/examples/typescript-eslint/tsconfig.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/examples/typescript-eslint/tsconfig.json @@ -0,0 +1 @@ +{} diff --git a/examples/typescript-tsx/package.json b/examples/typescript-tsx/package.json index 80507973ca..4ac7793329 100644 --- a/examples/typescript-tsx/package.json +++ b/examples/typescript-tsx/package.json @@ -3,20 +3,18 @@ "private": true, "version": "1.0.0", "scripts": { - "dev": "nuxt-ts", - "build": "nuxt-ts build", - "start": "nuxt-ts start", - "generate": "nuxt-ts generate", - "lint": "tslint --project .", - "lint:fix": "tslint --project . --fix", + "dev": "nuxt", + "build": "nuxt build", + "start": "nuxt start", + "generate": "nuxt generate", "post-update": "yarn upgrade --latest", "watch:css": "tcm components -w" }, "dependencies": { - "nuxt-ts": "latest" + "nuxt": "latest" }, "devDependencies": { - "tslint-config-standard": "^8.0.1", + "@nuxt/typescript": "latest", "typed-css-modules": "^0.3.7" } } diff --git a/examples/typescript-tsx/tsconfig.json b/examples/typescript-tsx/tsconfig.json index fe19900507..e19104a826 100644 --- a/examples/typescript-tsx/tsconfig.json +++ b/examples/typescript-tsx/tsconfig.json @@ -1,8 +1,6 @@ { - "extends": "@nuxt/typescript", "compilerOptions": { - "baseUrl": ".", - "noImplicitThis": true, - "types": ["@types/node", "@nuxt/vue-app"] + "jsx": "preserve", + "noImplicitThis": true } } diff --git a/examples/typescript-tsx/tslint.json b/examples/typescript-tsx/tslint.json deleted file mode 100644 index 0c17b301f4..0000000000 --- a/examples/typescript-tsx/tslint.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "defaultSeverity": "error", - "extends": ["tslint-config-standard"], - "rules": { - "prefer-const": true - } -} diff --git a/examples/typescript-vuex/package.json b/examples/typescript-vuex/package.json index 767f9cd8ef..1648346119 100644 --- a/examples/typescript-vuex/package.json +++ b/examples/typescript-vuex/package.json @@ -3,20 +3,19 @@ "private": true, "dependencies": { "axios": "^0.18.0", - "nuxt-ts": "latest", + "nuxt": "latest", "tachyons": "^4.11.1", "vue-property-decorator": "^7.3.0", "vuex-class": "^0.3.1" }, "scripts": { - "dev": "nuxt-ts", - "build": "nuxt-ts build", - "start": "nuxt-ts start", - "generate": "nuxt-ts generate", - "lint": "tslint --project .", + "dev": "nuxt", + "build": "nuxt build", + "start": "nuxt start", + "generate": "nuxt generate", "post-update": "yarn upgrade --latest" }, "devDependencies": { - "tslint-config-standard": "^8.0.1" + "@nuxt/typescript": "latest" } } diff --git a/examples/typescript-vuex/tsconfig.json b/examples/typescript-vuex/tsconfig.json index 6b563db445..0967ef424b 100644 --- a/examples/typescript-vuex/tsconfig.json +++ b/examples/typescript-vuex/tsconfig.json @@ -1,11 +1 @@ -{ - "extends": "@nuxt/typescript", - "compilerOptions": { - "baseUrl": ".", - "noImplicitAny": false, - "types": [ - "@types/node", - "@nuxt/vue-app" - ] - } -} +{} diff --git a/examples/typescript-vuex/tslint.json b/examples/typescript-vuex/tslint.json deleted file mode 100644 index 085d45bd4b..0000000000 --- a/examples/typescript-vuex/tslint.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "defaultSeverity": "error", - "extends": [ - "tslint-config-standard" - ], - "rules": { - "prefer-const": true - } -} diff --git a/examples/typescript/package.json b/examples/typescript/package.json index aa696b9fc4..5596e3b173 100644 --- a/examples/typescript/package.json +++ b/examples/typescript/package.json @@ -2,18 +2,17 @@ "version": "1.0.0", "private": true, "dependencies": { - "nuxt-ts": "latest", + "nuxt": "latest", "vue-property-decorator": "^7.3.0" }, "scripts": { - "dev": "nuxt-ts", - "build": "nuxt-ts build", - "start": "nuxt-ts start", - "generate": "nuxt-ts generate", - "lint": "tslint --project .", + "dev": "nuxt", + "build": "nuxt build", + "start": "nuxt start", + "generate": "nuxt generate", "post-update": "yarn upgrade --latest" }, "devDependencies": { - "tslint-config-standard": "^8.0.1" + "@nuxt/typescript": "latest" } } diff --git a/examples/typescript/tsconfig.json b/examples/typescript/tsconfig.json index e088a2e41c..0967ef424b 100644 --- a/examples/typescript/tsconfig.json +++ b/examples/typescript/tsconfig.json @@ -1,10 +1 @@ -{ - "extends": "@nuxt/typescript", - "compilerOptions": { - "baseUrl": ".", - "types": [ - "@types/node", - "@nuxt/vue-app" - ] - } -} +{} diff --git a/examples/typescript/tslint.json b/examples/typescript/tslint.json deleted file mode 100644 index 085d45bd4b..0000000000 --- a/examples/typescript/tslint.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "defaultSeverity": "error", - "extends": [ - "tslint-config-standard" - ], - "rules": { - "prefer-const": true - } -} diff --git a/packages/cli/src/command.js b/packages/cli/src/command.js index d09e9b4a68..7108d0450f 100644 --- a/packages/cli/src/command.js +++ b/packages/cli/src/command.js @@ -1,9 +1,12 @@ + +import path from 'path' import consola from 'consola' import minimist from 'minimist' 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 * as imports from './imports' export default class NuxtCommand { @@ -73,7 +76,10 @@ export default class NuxtCommand { 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 options = Object.assign(config, extraOptions) diff --git a/packages/cli/src/utils/index.js b/packages/cli/src/utils/index.js index b2f22d13b6..de6ce42ad5 100644 --- a/packages/cli/src/utils/index.js +++ b/packages/cli/src/utils/index.js @@ -1,5 +1,4 @@ import path from 'path' -import { existsSync } from 'fs' import consola from 'consola' import esm from 'esm' import exit from 'exit' @@ -11,14 +10,14 @@ import prettyBytes from 'pretty-bytes' import env from 'std-env' import { successBox, warningBox } from './formatting' -export const requireModule = process.env.NUXT_TS ? require : esm(module, { +const esmOptions = { cache: false, cjs: { cache: true, vars: true, namedExports: true } -}) +} export const eventsMapping = { add: { icon: '+', color: 'green', action: 'Created' }, @@ -26,18 +25,23 @@ export const eventsMapping = { 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) { - const rootDir = getRootDir(argv) - const nuxtConfigFile = getNuxtConfigFile(argv) - + const rootDir = path.resolve(argv._[0] || '.') + let nuxtConfigFile let options = {} - if (existsSync(nuxtConfigFile)) { - delete require.cache[nuxtConfigFile] - options = requireModule(nuxtConfigFile) || {} + try { + nuxtConfigFile = require.resolve(path.resolve(rootDir, argv['config-file'])) + } 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) { options = options.default } @@ -56,9 +60,8 @@ export async function loadNuxtConfig(argv) { // Keep _nuxtConfigFile for watching options._nuxtConfigFile = nuxtConfigFile - } else if (argv['config-file'] !== defaultNuxtConfigFile) { - consola.fatal('Could not load config file: ' + argv['config-file']) } + if (typeof options.rootDir !== 'string') { options.rootDir = rootDir } diff --git a/packages/cli/src/utils/typescript.js b/packages/cli/src/utils/typescript.js new file mode 100644 index 0000000000..efb0d7b60f --- /dev/null +++ b/packages/cli/src/utils/typescript.js @@ -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 +} diff --git a/packages/cli/test/unit/__snapshots__/command.test.js.snap b/packages/cli/test/unit/__snapshots__/command.test.js.snap index fc6f1cf37f..7e94e0af4a 100644 --- a/packages/cli/test/unit/__snapshots__/command.test.js.snap +++ b/packages/cli/test/unit/__snapshots__/command.test.js.snap @@ -14,7 +14,7 @@ exports[`cli/command builds help text 1`] = ` --universal, -u Launch in Universal mode (default) --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 browsers, e.g. server, client and false diff --git a/packages/config/src/config/build.js b/packages/config/src/config/build.js index 8b0919d37a..3bde85fbc6 100644 --- a/packages/config/src/config/build.js +++ b/packages/config/src/config/build.js @@ -54,7 +54,9 @@ export default () => ({ }, vueStyle: {} }, - useForkTsChecker: process.env.NUXT_TS === 'true', + typescript: { + typeCheck: true + }, styleResources: {}, plugins: [], terser: {}, diff --git a/packages/config/src/config/index.js b/packages/config/src/config/index.js index 0e6fe2fc75..aa36e71330 100644 --- a/packages/config/src/config/index.js +++ b/packages/config/src/config/index.js @@ -10,7 +10,7 @@ import router from './router' import server from './server' 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 = {}) { if (!options.env) { diff --git a/packages/config/src/options.js b/packages/config/src/options.js index 639afc6cb8..896d40e7e1 100644 --- a/packages/config/src/options.js +++ b/packages/config/src/options.js @@ -84,7 +84,7 @@ export function getNuxtConfig(_options) { // Default value for _nuxtConfigFile if (!options._nuxtConfigFile) { - options._nuxtConfigFile = path.resolve(options.rootDir, defaultNuxtConfigFile) + options._nuxtConfigFile = path.resolve(options.rootDir, `${defaultNuxtConfigFile}.js`) } // Watch for _nuxtConfigFile changes diff --git a/packages/config/test/__snapshots__/options.test.js.snap b/packages/config/test/__snapshots__/options.test.js.snap index e64e2de92f..41cf6a3d4b 100644 --- a/packages/config/test/__snapshots__/options.test.js.snap +++ b/packages/config/test/__snapshots__/options.test.js.snap @@ -131,7 +131,9 @@ Object { "templates": Array [], "terser": Object {}, "transpile": Array [], - "useForkTsChecker": false, + "typescript": Object { + "typeCheck": true, + }, "watch": Array [], }, "buildDir": "/var/nuxt/test/.nuxt", diff --git a/packages/config/test/config/__snapshots__/index.test.js.snap b/packages/config/test/config/__snapshots__/index.test.js.snap index 83f9a88a7a..26e25a4840 100644 --- a/packages/config/test/config/__snapshots__/index.test.js.snap +++ b/packages/config/test/config/__snapshots__/index.test.js.snap @@ -121,7 +121,9 @@ Object { "templates": Array [], "terser": Object {}, "transpile": Array [], - "useForkTsChecker": false, + "typescript": Object { + "typeCheck": true, + }, "watch": Array [], }, "buildDir": ".nuxt", @@ -450,7 +452,9 @@ Object { "templates": Array [], "terser": Object {}, "transpile": Array [], - "useForkTsChecker": false, + "typescript": Object { + "typeCheck": true, + }, "watch": Array [], }, "buildDir": ".nuxt", diff --git a/packages/typescript/package.json b/packages/typescript/package.json index ff9ed23aea..24c95df1bf 100644 --- a/packages/typescript/package.json +++ b/packages/typescript/package.json @@ -4,8 +4,7 @@ "repository": "nuxt/nuxt.js", "license": "MIT", "files": [ - "dist", - "tsconfig.json" + "dist" ], "main": "dist/typescript.js", "dependencies": { @@ -22,15 +21,11 @@ "@types/webpack-bundle-analyzer": "^2.13.1", "@types/webpack-dev-middleware": "^2.0.2", "@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", "fs-extra": "^7.0.1", - "std-env": "^2.2.1", + "lodash": "^4.17.11", "ts-loader": "^5.3.3", "ts-node": "^8.0.3", - "tslint": "^5.14.0", "typescript": "^3.3.3333" }, "publishConfig": { diff --git a/packages/typescript/src/index.js b/packages/typescript/src/index.js index 6cc30c8c49..dbd13c56b9 100644 --- a/packages/typescript/src/index.js +++ b/packages/typescript/src/index.js @@ -1,53 +1,57 @@ -import chalk from 'chalk' -import consola from 'consola' -import env from 'std-env' -import { prompt } from 'enquirer' -import { existsSync, writeJSON } from 'fs-extra' +import { readJSON, writeJSON } from 'fs-extra' import { register } from 'ts-node' +import defaultsDeep from 'lodash/defaultsDeep' -async function generateTsConfig(tsConfigPath) { - const configToExtend = '@nuxt/typescript' - await writeJSON(tsConfigPath, { - extends: configToExtend, - compilerOptions: { - baseUrl: '.', - types: [ - '@types/node', - '@nuxt/vue-app' +export const defaultTsJsonConfig = { + 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: '.', + paths: { + '~/*': [ + './*' + ], + '@/*': [ + './*' ] - } - }, { spaces: 2 }) - consola.info(`Extending ${chalk.bold.blue(`node_modules/${configToExtend}/tsconfig.json`)}`) - consola.success(`Generated successfully at ${chalk.bold.green(tsConfigPath)}`) + }, + types: [ + '@types/node', + '@nuxt/vue-app' + ] + } } let _setup = false -export async function setup(tsConfigPath) { +export async function setup(tsConfigPath, options = {}) { 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 - }) + const config = await readJSON(tsConfigPath) + await writeJSON(tsConfigPath, defaultsDeep(config, defaultTsJsonConfig), { spaces: 2 }) - if (confirmGeneration) { - await generateTsConfig(tsConfigPath) - } - } // https://github.com/TypeStrong/ts-node register({ project: tsConfigPath, compilerOptions: { module: 'commonjs' }, - transpileOnly: process.argv[2] === 'start' + ...options }) } diff --git a/packages/typescript/test/setup.test.js b/packages/typescript/test/setup.test.js index 3646048f49..837442a07a 100644 --- a/packages/typescript/test/setup.test.js +++ b/packages/typescript/test/setup.test.js @@ -1,12 +1,9 @@ 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 { setup as setupTypeScript } from '@nuxt/typescript' +import { defaultTsJsonConfig, setup as setupTypeScript } from '@nuxt/typescript' jest.mock('ts-node') -jest.mock('enquirer', () => ({ - prompt: jest.fn(() => ({ confirmGeneration: true })) -})) describe('typescript setup', () => { const rootDir = 'tmp' @@ -15,21 +12,12 @@ describe('typescript setup', () => { beforeAll(async () => { // We're assuming that rootDir provided to setupTypeScript is existing so we create the tested one await mkdirp(rootDir) + await writeJSON(tsConfigPath, {}) 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('tsconfig.json has been updated with defaults', async () => { + expect(await readJSON(tsConfigPath)).toEqual(defaultTsJsonConfig) }) test('ts-node has been registered once', async () => { @@ -41,13 +29,12 @@ describe('typescript setup', () => { project: tsConfigPath, compilerOptions: { module: 'commonjs' - }, - transpileOnly: false + } }) }) afterAll(async () => { // Clean workspace by removing the temporary folder (and the generated tsconfig.json at the same time) - await remove(tsConfigPath) + await remove(rootDir) }) }) diff --git a/packages/typescript/tsconfig.json b/packages/typescript/tsconfig.json deleted file mode 100644 index d4a6699b61..0000000000 --- a/packages/typescript/tsconfig.json +++ /dev/null @@ -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": { - "~/*": [ - "./*" - ], - "@/*": [ - "./*" - ] - } - } -} diff --git a/packages/webpack/src/config/client.js b/packages/webpack/src/config/client.js index 46a484613b..6642105240 100644 --- a/packages/webpack/src/config/client.js +++ b/packages/webpack/src/config/client.js @@ -1,5 +1,4 @@ import path from 'path' -import fs from 'fs' import querystring from 'querystring' import consola from 'consola' import webpack from 'webpack' @@ -77,7 +76,7 @@ export default class WebpackClientConfig extends WebpackBaseConfig { 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 if (buildOptions.ssr) { @@ -140,21 +139,16 @@ export default class WebpackClientConfig extends WebpackBaseConfig { // TypeScript type checker // 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) { - const forkTsCheckerResolvedPath = this.buildContext.nuxt.resolver.resolveModule('fork-ts-checker-webpack-plugin') - if (forkTsCheckerResolvedPath) { - const ForkTsCheckerWebpackPlugin = require(forkTsCheckerResolvedPath) - plugins.push(new ForkTsCheckerWebpackPlugin(Object.assign({ - vue: true, - 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: (tslintPath => fs.existsSync(tslintPath) && tslintPath)(path.resolve(rootDir, 'tslint.json')), - formatter: 'codeframe', - logger: consola - }, buildOptions.useForkTsChecker))) - } else { - consola.warn('You need to install `fork-ts-checker-webpack-plugin` as devDependency to enable TypeScript type checking !') - } + if (_typescript && buildOptions.typescript && buildOptions.typescript.typeCheck && !this.isModern && this.loaders.ts.transpileOnly) { + // We assume that "_typescript" being truthy means @nuxt/typescript is installed <=> fork-ts-checker-webpack-plugin is installed + const ForkTsCheckerWebpackPlugin = require(this.buildContext.nuxt.resolver.resolveModule('fork-ts-checker-webpack-plugin')) + plugins.push(new ForkTsCheckerWebpackPlugin(Object.assign({ + vue: true, + tsconfig: path.resolve(rootDir, 'tsconfig.json'), + tslint: false, // We recommend using ESLint so we set this option to `false` by default + formatter: 'codeframe', + logger: consola + }, buildOptions.typescript.typeCheck))) } return plugins diff --git a/test/fixtures/typescript/tsconfig.json b/test/fixtures/typescript/tsconfig.json index 6b563db445..5829f5af81 100644 --- a/test/fixtures/typescript/tsconfig.json +++ b/test/fixtures/typescript/tsconfig.json @@ -1,8 +1,30 @@ { - "extends": "@nuxt/typescript", "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, + "noEmit": true, + "baseUrl": ".", + "paths": { + "~/*": [ + "./*" + ], + "@/*": [ + "./*" + ] + }, "types": [ "@types/node", "@nuxt/vue-app" diff --git a/test/unit/typescript.modern.test.js b/test/unit/typescript.modern.test.js index f6105747be..4f934f653e 100644 --- a/test/unit/typescript.modern.test.js +++ b/test/unit/typescript.modern.test.js @@ -8,7 +8,7 @@ describe('typescript modern', () => { beforeAll(async () => { 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() }) diff --git a/yarn.lock b/yarn.lock index cb1b31086a..860abde92f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2184,7 +2184,7 @@ ansi-align@^3.0.0: dependencies: string-width "^3.0.0" -ansi-colors@^3.0.0, ansi-colors@^3.2.1: +ansi-colors@^3.0.0: version "3.2.4" resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== @@ -4284,13 +4284,6 @@ enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: memory-fs "^0.4.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: version "1.1.2" resolved "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"