The skill is in the toss. React+ TS type inference improves development efficiency. And now Vue3. X supports TS, but Vue3. If Vue2. X also supports TS, it will improve our development efficiency. However, Vue2- CLI Webpack3.x presents various errors in Typescript compilation, and Webpack4.x has greatly improved packaging speed and efficiency, so we decided to upgrade Webpack and use the latest Webpack4.x to support Typescript. No more nonsense, on the configuration:

Create a Vue project

$NPM install -g vue-cli # create a new project based on webpack template $vue init webpack vue-ts-project $CD vue-ts-project # $NPM run dev = $NPM run dev = $NPM run devCopy the code

Start by upgrading Webpack to 4.x

Upgrade the NPM package in package.json

webpack

"webpack": "^ 3.6.0"= >"^ 4.29.6"
"webpack-bundle-analyzer": "^ 2.9.0"= >"^ 3.1.0"
"webpack-cli": "^ 3.3.0" (ADD)
"webpack-dev-server": "^ 2.9.1." "= >"^ 3.1.11"
"webpack-merge": "^ 4.1.0." "= >"^ 2"
Copy the code

loader

"css-loader": "^ 0.28.0"= >"^ 2.1.1"
"file-loader": "^ 1.1.4." "= >"^ 3.0.1." "
"inject-loader": "^ 3.0.0"= >"^ 4.0.1." "
"postcss-loader": "^ mid-atlantic moved." "= >"^ 3.0.0"
"url-loader": "^ 0.5.8"= >"^ 1.1.2." "
"vue-loader": "^ 13.3.0"= >"^ 15.7.0"
"vue-style-loader": "^ 3.0.1." "= >"^ 4.1.2." "
"vue-template-compiler": "^ 2.5.2." "= >"^ 2.6.9." "
Copy the code

plugin

"copy-webpack-plugin": "^ 4.0.1." "= >"^ 5.0.1." "
"friendly-errors-webpack-plugin": "^ 1.6.1." "= >"^ 1.7.0"
"html-webpack-plugin": "^ 2.30.1"= >"^ 3.2.0"
"optimize-css-assets-webpack-plugin": "^ 3.2.0"= >"^ 5.0.1." "
"extract-text-webpack-plugin": "^ 3.0.0"  (DEL)
"mini-css-extract-plugin": "^ 0.5.0" (ADD)
Copy the code

eslint

"eslint": "^ 4.15.0"= >"^ 4.19.1"
"eslint-config-standard": "^ 10.2.1"= >"^ 11.0.0"
"eslint-friendly-formatter": "^ 3.0.0"= >"^ 4.0.1." "
"eslint-loader": "^ 1.7.1." "= >"^ 2.0.0." "
"eslint-plugin-import": "^ 2.7.0"= >"^ 2.12.0"
"eslint-plugin-node": "^ 5.2.0." "= >"^ the 6.0.1." "
"eslint-plugin-promise": "^ 3.4.0"= >"^ 3.7.0"
"eslint-plugin-standard": "^ 3.0.1." "= >"^ 3.1.0"
"eslint-plugin-vue": "^ 4.0.0"= >"^ 4.5.0." "
Copy the code

Configuration changes

build/webpack.base.conf.js

+ const { VueLoaderPlugin } = require('vue-loader')

module.exports = {
+  plugins: [
+    new VueLoaderPlugin()
+  ],
   resolve: {
     extensions: ['.js'.'.ts'.'.vue'.'.json'].alias: {
      'vue$': 'vue/dist/vue.esm.js'.The '@': resolve('src'),}}}Copy the code

build/webpack.prod.conf.js

-  // const ExtractTextPlugin = require('extract-text-webpack-plugin')
-  // const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
+  const MiniCssExtractPlugin = require('mini-css-extract-plugin')
+  const { VueLoaderPlugin } = require('vue-loader')

   const webpackConfig = merge(baseWebpackConfig, {
     
+    optimization: {
+      minimize: true,
+      splitChunks: {
+        cacheGroups: {
+          vendors: {
+            test: /[\\/]node_modules[\\/]/,
+            chunks: 'initial',
+            name: 'vendors', + +}'async-vendors': {
+            test: /[\\/]node_modules[\\/]/,
+            minChunks: 2,
+            chunks: 'async',
+            name: 'async-vendors'
+          }
+        }
+       },
+       runtimeChunk: { name: 'runtime'+}},plugins: [+new MiniCssExtractPlugin({
+        filename: utils.assetsPath('css/[name].[contenthash].css'),
+        allChunks: true, - +})// new ExtractTextPlugin({
-      // filename: utils.assetsPath('css/[name].[contenthash].css'),
-      // allChunks: true,
-      // }),
-      // new UglifyJsPlugin({
-      // uglifyOptions: {
-      // compress: {
-      // warnings: false
-      / /}
-      / /},
-      // sourceMap: config.build.productionSourceMap,
-      // parallel: true
-      // }),
-      // new webpack.optimize.CommonsChunkPlugin({
-      // name: 'vendor',
-      // minChunks (module) {
-      // return (
-      // module.resource && /\.js$/.test(module.resource) &&
-      // module.resource.indexOf(
-      // path.join(__dirname, '.. /node_modules')
-      / /) = = = 0
-      / /)
-      // }
-      // }),
-      // new webpack.optimize.CommonsChunkPlugin({
-      // name: 'manifest',
-      // minChunks: Infinity
-      // }),
-      // new webpack.optimize.CommonsChunkPlugin({
-      // name: 'app',
-      // async: 'vendor-async',
-      // children: true,
-      // minChunks: 3
-      // }),]}Copy the code

build/utils.js

- // const ExtractTextPlugin = require('extract-text-webpack-plugin')
+ const MiniCssExtractPlugin = require('mini-css-extract-plugin')

  function generateLoaders (loader, loaderOptions) {
    const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]

    if (loader) {
      loaders.push({
        loader: loader + '-loader'.options: Object.assign({}, loaderOptions, {
          sourceMap: options.sourceMap
        })
      })
    }

-   // Extract CSS when that option is specified
-   // (which is the case during production build)
-   // if (options.extract) {
-   // return ExtractTextPlugin.extract({
-   // use: loaders,
-   // fallback: 'vue-style-loader'
-   / /})
-   // } else {
-   // return ['vue-style-loader'].concat(loaders)
-   // }
+   return [
+     options.extract ? MiniCssExtractPlugin.loader : 'vue-style-loader',
+   ].concat(loaders)
  }
Copy the code

Add Typescript support

Install the NPM package

$ npm install typescript ts-loader --save-dev
$ npm install vue-class-component vue-property-decorator --save-dev
Copy the code

Create the vue-shim.d.ts file under SRC

declare module "*.vue" {
  import Vue from "vue"
  export default Vue
}
Copy the code

Create a new tsconfig.json file in the project root directory

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true."experimentalDecorators": true."allowJs": true."module": "esnext"."target": "es5"."moduleResolution": "node"."isolatedModules": true."lib": [
      "dom"."es5"."es6"."es7"."es2015.promise"."scripthost"]."sourceMap": true."pretty": true."strictFunctionTypes": false."importHelpers": true
  },
  "include": [
    "src/**/*"]."exclude": [
    "node_modules"]}Copy the code

Change the main.js extension to main.ts

+ import App from './App.vue'
Copy the code

Modify the webpack.base.conf.js configuration

  entry: {
-    app: './src/main.js'
+    app: './src/main.ts'
  },
  resolve: {
+   extensions: ['.js'.'.vue'.'.json'.'.ts'].alias: {
      'vue$': 'vue/dist/vue.esm.js'.The '@': resolve('src'),}},module: {
    rules: [
    // ...
      {
        test: /\.tsx? $/,
        loader: 'ts-loader'.exclude: /node_modules/,
        options: {
          appendTsSuffixTo: [/\.vue$/],},include: [resolve('src')]}// ...]},Copy the code

Modify vUE components

<template>
  <div>{{msg}}</div>
</template>

<script lang="ts">
import Vue from 'vue'
import { Component } from 'vue-property-decorator'
import HelloWorld from '@/components/HelloWorld.vue'

@Component({
  components: {
    HelloWorld
  }
})
export default class App extends Vue {
  msg = 'hello world'
}
</script>
Copy the code

happy hacking

Complete code reference documentation