技术在于折腾。之前一直用React+ts,类型推导提高了开发效率,真香。而且现在Vue3.x也支持ts了,但是Vue3.x天生对IE的兼容性差,让我们望而退步。如果Vue2.x也支持ts,就提高我们开发效率。但是Vue2-cli自带的Webpack3.x在编译Typescript各种报错,而且Webpack4.x中对于打包速度,效率等有了很大提升,故决定升级Webpack,用最新的Webpack4.x支持Typescript。废话不多说了,上配置:
新建Vue项目
# 全局安装 vue-cli
$ npm install -g vue-cli
# 创建一个基于 webpack 模板的新项目
$ vue init webpack vue-ts-project
$ cd vue-ts-project
# 安装依赖
$ npm install
# 然后就可以运行看到界面了
$ npm run dev
先将Webpack升级到4.x
升级package.json中npm包
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"
"inject-loader": "^3.0.0" => "^4.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"
配置修改
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',
'@': resolve('src'),
}
}
}
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
- // }),
]
}
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)
}
添加Typescript支持
安装npm包
$ npm install typescript ts-loader --save-dev
$ npm install vue-class-component vue-property-decorator --save-dev
在src下新建vue-shim.d.ts文件
declare module "*.vue" {
import Vue from "vue"
export default Vue
}
在项目根目录下新建tsconfig.json文件
{
"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"
]
}
将main.js扩展名更改为main.ts
+ import App from './App.vue'
修改webpack.base.conf.js配置
entry: {
- app: './src/main.js'
+ app: './src/main.ts'
},
resolve: {
+ extensions: ['.js', '.vue', '.json', '.ts'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
},
module: {
rules: [
// ...
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/\.vue$/],
},
include: [resolve('src')]
}
// ...
]
},
改造vue组件
<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>