diff --git a/package.json b/package.json index d5e6984087..20aedf3698 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "rollup-plugin-node-resolve": "^4.0.0", "rollup-plugin-replace": "^2.1.0", "sort-package-json": "^1.17.1", + "ts-loader": "^5.3.1", "typescript": "^3.2.2", "vue-jest": "^3.0.2", "vue-property-decorator": "^7.2.0" diff --git a/packages/babel-preset-app/package.json b/packages/babel-preset-app/package.json index b84ad118f0..833a0a1c5d 100644 --- a/packages/babel-preset-app/package.json +++ b/packages/babel-preset-app/package.json @@ -17,7 +17,6 @@ "@babel/plugin-syntax-jsx": "^7.2.0", "@babel/plugin-transform-runtime": "^7.2.0", "@babel/preset-env": "^7.2.0", - "@babel/preset-typescript": "^7.1.0", "@babel/runtime": "^7.2.0", "babel-helper-vue-jsx-merge-props": "^2.0.3", "babel-plugin-transform-vue-jsx": "^4.0.1" diff --git a/packages/babel-preset-app/src/index.js b/packages/babel-preset-app/src/index.js index 84888046b7..79add0f622 100644 --- a/packages/babel-preset-app/src/index.js +++ b/packages/babel-preset-app/src/index.js @@ -92,11 +92,6 @@ module.exports = (context, options = {}) => { } ]) - // TypeScript preset - if (options.typescript) { - presets.push(require('@babel/preset-typescript')) - } - plugins.push( require('@babel/plugin-syntax-dynamic-import'), [require('@babel/plugin-proposal-decorators'), { diff --git a/packages/builder/src/builder.js b/packages/builder/src/builder.js index 08c8cc2954..9196229faa 100644 --- a/packages/builder/src/builder.js +++ b/packages/builder/src/builder.js @@ -45,10 +45,7 @@ export default class Builder { restart: null } - this.supportedExtensions = ['vue', 'js'] - if (this.options.build.typescript) { - this.supportedExtensions.push('ts', 'tsx') - } + this.supportedExtensions = ['vue', 'js', 'ts'] // Helper to resolve build paths this.relativeToBuild = (...args) => @@ -326,8 +323,7 @@ export default class Builder { templateVars.router.routes = createRoutes( Object.values(files), this.options.srcDir, - this.options.dir.pages, - this.supportedExtensions + this.options.dir.pages ) } else { // If user defined a custom method to create routes templateVars.router.routes = this.options.build.createRoutes( diff --git a/packages/common/src/utils.js b/packages/common/src/utils.js index d02d72145d..939a7287c3 100644 --- a/packages/common/src/utils.js +++ b/packages/common/src/utils.js @@ -316,7 +316,8 @@ const sortRoutes = function sortRoutes(routes) { return routes } -export const createRoutes = function createRoutes(files, srcDir, pagesDir, supportedExtensions = ['vue', 'js']) { +export const createRoutes = function createRoutes(files, srcDir, pagesDir) { + const supportedExtensions = ['vue', 'js', 'ts'] const routes = [] files.forEach((file) => { const keys = file diff --git a/packages/config/src/config/build.js b/packages/config/src/config/build.js index bf1b57891a..12381d7079 100644 --- a/packages/config/src/config/build.js +++ b/packages/config/src/config/build.js @@ -5,7 +5,6 @@ export default () => ({ analyze: false, profile: process.argv.includes('--profile'), extractCSS: false, - typescript: false, crossorigin: undefined, cssSourceMap: undefined, ssr: undefined, diff --git a/packages/config/src/options.js b/packages/config/src/options.js index 05b8ca1274..bc7cb96c1d 100644 --- a/packages/config/src/options.js +++ b/packages/config/src/options.js @@ -118,10 +118,7 @@ export function getNuxtConfig(_options) { ) ) - const mandatoryExtensions = ['js', 'mjs'] - if (options.build.typescript) { - mandatoryExtensions.push('ts') - } + const mandatoryExtensions = ['js', 'mjs', 'ts'] options.extensions = mandatoryExtensions .filter(ext => !options.extensions.includes(ext)) diff --git a/packages/webpack/src/config/base.js b/packages/webpack/src/config/base.js index 3a4d6f3b46..8c1e735b49 100644 --- a/packages/webpack/src/config/base.js +++ b/packages/webpack/src/config/base.js @@ -75,8 +75,7 @@ export default class WebpackBaseConfig { [ require.resolve('@nuxt/babel-preset-app'), { - buildTarget: this.isServer ? 'server' : 'client', - typescript: this.options.build.typescript + buildTarget: this.isServer ? 'server' : 'client' } ] ] @@ -216,7 +215,7 @@ export default class WebpackBaseConfig { ] }, { - test: this.options.build.typescript ? /\.(j|t)sx?$/ : /\.jsx?$/, + test: /\.jsx?$/, exclude: (file) => { // not exclude files outside node_modules if (!/node_modules/.test(file)) { @@ -231,6 +230,14 @@ export default class WebpackBaseConfig { options: this.getBabelOptions() }) }, + { + test: /\.ts$/, + loader: 'ts-loader', + options: { + transpileOnly: true, + appendTsSuffixTo: [/\.vue$/] + } + }, { test: /\.css$/, oneOf: styleLoader.apply('css') @@ -377,10 +384,6 @@ export default class WebpackBaseConfig { config() { // Prioritize nested node_modules in webpack search path (#2558) const webpackModulesDir = ['node_modules'].concat(this.options.modulesDir) - let extensionsToResolve = ['.wasm', '.mjs', '.js', '.json', '.vue', '.jsx'] - if (this.options.build.typescript) { - extensionsToResolve = extensionsToResolve.concat(['.ts', '.tsx']) - } const config = { name: this.name, @@ -393,7 +396,7 @@ export default class WebpackBaseConfig { hints: this.options.dev ? false : 'warning' }, resolve: { - extensions: extensionsToResolve, + extensions: ['.wasm', '.mjs', '.js', '.json', '.vue', '.jsx', '.ts'], alias: this.alias(), modules: webpackModulesDir }, diff --git a/test/fixtures/typescript-custom/layouts/default.vue b/test/fixtures/typescript-custom/layouts/default.vue new file mode 100644 index 0000000000..3ad56798b1 --- /dev/null +++ b/test/fixtures/typescript-custom/layouts/default.vue @@ -0,0 +1,10 @@ + + + diff --git a/test/fixtures/typescript-custom/modules/typescript.js b/test/fixtures/typescript-custom/modules/typescript.js new file mode 100644 index 0000000000..eb20cbfe53 --- /dev/null +++ b/test/fixtures/typescript-custom/modules/typescript.js @@ -0,0 +1,19 @@ +export default function typeScriptModule() { + // Add .ts extension for store, middleware and more + this.nuxt.options.extensions.push('ts') + + // Extend build + this.extendBuild((config) => { + // 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') + }) +} diff --git a/test/fixtures/typescript-custom/nuxt.config.js b/test/fixtures/typescript-custom/nuxt.config.js new file mode 100644 index 0000000000..ee6e904831 --- /dev/null +++ b/test/fixtures/typescript-custom/nuxt.config.js @@ -0,0 +1,3 @@ +export default { + modules: ['~/modules/typescript'] +} diff --git a/test/fixtures/typescript-custom/pages/about.ts b/test/fixtures/typescript-custom/pages/about.ts new file mode 100644 index 0000000000..1218ba9b58 --- /dev/null +++ b/test/fixtures/typescript-custom/pages/about.ts @@ -0,0 +1,8 @@ +import Vue from 'vue' + +export default Vue.extend({ + name: 'About', + render (h) { + return h('div', 'About Page') + } +}) diff --git a/test/fixtures/typescript-custom/pages/index.vue b/test/fixtures/typescript-custom/pages/index.vue new file mode 100644 index 0000000000..d29cf5e56e --- /dev/null +++ b/test/fixtures/typescript-custom/pages/index.vue @@ -0,0 +1,12 @@ + + + diff --git a/test/fixtures/typescript-custom/tsconfig.json b/test/fixtures/typescript-custom/tsconfig.json new file mode 100644 index 0000000000..43021bdaf1 --- /dev/null +++ b/test/fixtures/typescript-custom/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "esnext", + "moduleResolution": "node", + "lib": ["esnext", "esnext.asynciterable", "dom"], + "esModuleInterop": true, + "experimentalDecorators": true, + "allowJs": true, + "sourceMap": true, + "strict": true, + "noImplicitAny": true, + "noEmit": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "baseUrl": ".", + "paths": { + "~/*": ["./*"] + } + } +} diff --git a/test/fixtures/typescript-custom/typescript-custom.test.js b/test/fixtures/typescript-custom/typescript-custom.test.js new file mode 100644 index 0000000000..7390f19b05 --- /dev/null +++ b/test/fixtures/typescript-custom/typescript-custom.test.js @@ -0,0 +1,3 @@ +import { buildFixture } from '../../utils/build' + +buildFixture('typescript-custom') diff --git a/test/fixtures/typescript/@types/process.d.ts b/test/fixtures/typescript/@types/process.d.ts deleted file mode 100644 index 648fe143b2..0000000000 --- a/test/fixtures/typescript/@types/process.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -declare namespace NodeJS { - interface Process { - browser: boolean - client: boolean - server: boolean - static: boolean - } -} diff --git a/test/fixtures/typescript/@types/shims-tsx.d.ts b/test/fixtures/typescript/@types/shims-tsx.d.ts deleted file mode 100644 index 22d8ef98a9..0000000000 --- a/test/fixtures/typescript/@types/shims-tsx.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import Vue, { VNode } from 'vue' - -declare global { - namespace JSX { - interface Element extends VNode {} - interface ElementClass extends Vue {} - interface IntrinsicElements { - [elemName: string]: any - } - } -} diff --git a/test/fixtures/typescript/layouts/default.vue b/test/fixtures/typescript/layouts/default.vue index 0526cdec9f..c0e0ef391d 100644 --- a/test/fixtures/typescript/layouts/default.vue +++ b/test/fixtures/typescript/layouts/default.vue @@ -6,8 +6,7 @@ import { Component, Vue } from 'vue-property-decorator' @Component({ - name: 'DefaultLayout', middleware: 'test' }) -export default class extends Vue {} +export default class DefaultLayout extends Vue {} diff --git a/test/fixtures/typescript/nuxt.config.js b/test/fixtures/typescript/nuxt.config.js index ed451654a6..d85bef0d04 100644 --- a/test/fixtures/typescript/nuxt.config.js +++ b/test/fixtures/typescript/nuxt.config.js @@ -1,8 +1,3 @@ export default { - plugins: [ - '~/plugins/plugin.ts' - ], - build: { - typescript: true - } + plugins: ['~/plugins/plugin'] } diff --git a/test/fixtures/typescript/pages/contact.tsx b/test/fixtures/typescript/pages/contact.tsx deleted file mode 100644 index b6d3cab018..0000000000 --- a/test/fixtures/typescript/pages/contact.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import Vue from 'vue' - -export default Vue.extend({ - name: 'Contact', - data () { - return { - message: 'Contact Page' - } - }, - render () { - return
{this.message}
- } -}) diff --git a/test/fixtures/typescript/pages/index.vue b/test/fixtures/typescript/pages/index.vue index f4cd80a770..d29cf5e56e 100644 --- a/test/fixtures/typescript/pages/index.vue +++ b/test/fixtures/typescript/pages/index.vue @@ -5,10 +5,8 @@ diff --git a/test/fixtures/typescript/pages/interface.vue b/test/fixtures/typescript/pages/interface.vue new file mode 100644 index 0000000000..6e21446eda --- /dev/null +++ b/test/fixtures/typescript/pages/interface.vue @@ -0,0 +1,22 @@ + + + diff --git a/test/fixtures/typescript/tsconfig.json b/test/fixtures/typescript/tsconfig.json index 31bd6e2208..43021bdaf1 100644 --- a/test/fixtures/typescript/tsconfig.json +++ b/test/fixtures/typescript/tsconfig.json @@ -1,13 +1,12 @@ { "compilerOptions": { - "target": "esnext", + "target": "es5", "module": "esnext", "moduleResolution": "node", "lib": ["esnext", "esnext.asynciterable", "dom"], "esModuleInterop": true, "experimentalDecorators": true, "allowJs": true, - "jsx": "preserve", "sourceMap": true, "strict": true, "noImplicitAny": true, diff --git a/test/unit/typescript-custom.test.js b/test/unit/typescript-custom.test.js new file mode 100644 index 0000000000..2e67c9d329 --- /dev/null +++ b/test/unit/typescript-custom.test.js @@ -0,0 +1,27 @@ +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('
Index Page
') + }) + + test('/about', async () => { + const { html } = await nuxt.server.renderRoute('/about') + expect(html).toContain('
About Page
') + }) + + // Close server and ask nuxt to stop listening to file changes + afterAll(async () => { + await nuxt.close() + }) +}) diff --git a/test/unit/typescript.test.js b/test/unit/typescript.test.js index f86e20ca59..3c5428c338 100644 --- a/test/unit/typescript.test.js +++ b/test/unit/typescript.test.js @@ -20,9 +20,9 @@ describe('typescript', () => { expect(html).toContain('
About Page
') }) - test('/contact', async () => { - const { html } = await nuxt.server.renderRoute('/contact') - expect(html).toContain('
Contact Page
') + test('/interface', async () => { + const { html } = await nuxt.server.renderRoute('/interface') + expect(html).toContain('
Interface Page
') }) // Close server and ask nuxt to stop listening to file changes diff --git a/yarn.lock b/yarn.lock index 0384e8efc2..f92b1152cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -364,13 +364,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-typescript@^7.2.0": - version "7.2.0" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.2.0.tgz#55d240536bd314dcbbec70fd949c5cabaed1de29" - integrity sha512-WhKr6yu6yGpGcNMVgIBuI9MkredpVc7Y3YR4UzEZmDztHoL6wV56YBHLhWnjO1EvId1B32HrD3DRFc+zSoKI1g== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-arrow-functions@^7.2.0": version "7.2.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550" @@ -587,14 +580,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-typescript@^7.1.0": - version "7.2.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.2.0.tgz#bce7c06300434de6a860ae8acf6a442ef74a99d1" - integrity sha512-EnI7i2/gJ7ZNr2MuyvN2Hu+BHJENlxWte5XygPvfj/MbvtOkWor9zcnHpMMQL2YYaaCcqtIvJUyJ7QVfoGs7ew== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-typescript" "^7.2.0" - "@babel/plugin-transform-unicode-regex@^7.2.0": version "7.2.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.2.0.tgz#4eb8db16f972f8abb5062c161b8b115546ade08b" @@ -659,14 +644,6 @@ js-levenshtein "^1.1.3" semver "^5.3.0" -"@babel/preset-typescript@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.1.0.tgz#49ad6e2084ff0bfb5f1f7fb3b5e76c434d442c7f" - integrity sha512-LYveByuF9AOM8WrsNne5+N79k1YxjNB6gmpCQsnuSBAcV8QUeB+ZUxQzL7Rz7HksPbahymKkq2qBR+o36ggFZA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-typescript" "^7.1.0" - "@babel/register@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/register/-/register-7.0.0.tgz#fa634bae1bfa429f60615b754fc1f1d745edd827" @@ -4028,7 +4005,7 @@ enhanced-resolve@^3.4.1: object-assign "^4.0.1" tapable "^0.2.7" -enhanced-resolve@^4.1.0: +enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== @@ -9915,7 +9892,7 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.0.1, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.6.0" resolved "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== @@ -10818,6 +10795,17 @@ tryer@^1.0.0: resolved "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== +ts-loader@^5.3.1: + version "5.3.1" + resolved "https://registry.npmjs.org/ts-loader/-/ts-loader-5.3.1.tgz#70614c8ec4354a9c8b89c9f97b2becb7a98a3980" + integrity sha512-fDDgpBH3SR8xlt2MasLdz3Yy611PQ/UY/KGyo7TgXhTRU/6sS8uGG0nJYnU1OdFBNKcoYbId1UTNaAOUn+i41g== + dependencies: + chalk "^2.3.0" + enhanced-resolve "^4.0.0" + loader-utils "^1.0.2" + micromatch "^3.1.4" + semver "^5.0.1" + tsconfig@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz#84538875a4dc216e5c4a5432b3a4dec3d54e91b7"