vue-cli2.x版本项目接入typescript

684 阅读2分钟

在typescript被第n+1次提起时,我终于开始将项目接入typescript了!!! typescript顾名思义,就是在js的基础上增加了类型(type)的概念

由于typescript对webapck等版本有要求,本文将针对webapck升级和typescript接入分开介绍

github链接: github.com/huisunyang/…

webpack升级

由于vue-cli2.x版本构建项目的webpack版本为3.x版本 无法支持typescript 故将其升级为4.x版本

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" => "^4.2.1"
loader
"css-loader": "^0.28.0" => "^2.1.1"
"file-loader": "^1.1.4" => "^3.0.1"
"postcss-loader": "^2.0.8" => "^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"
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)
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" => "^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"
配置修改
webapck.base.conf.js
+  const { VueLoaderPlugin } = require('vue-loader')
...
plugins: [
+   new VueLoaderPlugin()
...
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,
        // 识别package.json中的sideEffects以剔除无用的模块,用来做tree-shake
      // 依赖于optimization.providedExports和optimization.usedExports
      sideEffects: true,
      // 取代 new webpack.optimize.ModuleConcatenationPlugin()
      concatenateModules: true,
      // 取代 new webpack.NoEmitOnErrorsPlugin(),编译错误时不打印输出资源。
      noEmitOnErrors: 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 VueLoaderPlugin(),
+   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
-  }),
util.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)
+ }
安装babel-plugin插件转换es6代码
npm install babel-plugin-transform-es2015-modules-commonjs -D
在项目根目录的.babelrc文件中加入:
"plugins": ["transform-es2015-modules-commonjs"]

typescript接入

安装相关依赖

npm install typescript ts-loader vue-property-decorator vue-class-component -D
修改webapck.base.conf.js
module: {
  rules: [
    ...
    {
      test: /\.tsx?$/i,
      use: [{
        loader: 'ts-loader',
        options: {
          appendTsSuffixTo: [/\.vue$/]
        }
      }],
      exclude: /node_modules/
    },
    
    ...
创建 vue 声明文件
在 src 目录下创建一个 shims-vue.d.ts 文件,这里叫啥无所谓,但是必须要以 .d.ts 为后缀
declare module '*.vue' {
  import Vue from 'vue'
  export default Vue
}
创建 tsconfig.json
在项目根目录下创建 tsconfig.json 文件. 这个文件可以使用 tsc 命令创建.
tsc --init
用 ts 替换 js 文件
src/App.vue
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'

@Component
export default class App extends Vue {
}
</script>
将js文件修改为ts文件 如main.js => mian.ts
修改 entry
module.exports = {
  entry: {
    app: './src/main.ts'
  }
  ...
}

npm run dev 就能成功运行了,项目就成功接入typescript