一、配置 webpack
首先通过:
npm init
来创建依赖文件:package.json
。
接下来安装 webpack,因为 webpack 属于开发环境下的依赖,所以安装在 devDependencies
里面。
npm install -D webpack webpack-cli webpack-dev-server
接下来整理和创建文件,文件结构为:
├─ package.json
│ webpack.config.js
│
├─public
│ index.html
│
└─src
main.js
先说下怎么获取这个文档树的,windows下打开 CMD:
tree /f > filetree.txt
tree
只能获取到文件夹,/f
能获取到具体文件,然后通过 > filetree.txt
写入文件。如果有 node_modules
的影响,我们可以忽略这个文件夹,这时的借助 git
来实现:
-I命令允许你使用正则匹配来排除掉你不想看到的文件夹
tree -I "node_modules"
也可以使用|同时排除掉多个文件夹:
tree -I "node_modules|cache|test_*"
有时候文件夹层级很深,我们只关心前两级的文件,可以使用如下-L :
tree -L 2
这时来看看各个文件的内容:
webpack.config.js:
module.exports = {
/*
mode:"production" | "development" | "none"
production:enable many optimizations for production builds
development:enabled useful tools for development
none: no defaults,没有默认,必须设置为production或development
Chosen mode tells webpack to use its built-in optimizations accordingly
*/
//--mode=development会将 process.env.NODE_ENV 的值设为 development。并启动相应的插件
mode:"development",
/* 基础目录,用于从配置中解析入口起点(entry point)和 loader */
// context: path.resolve(__dirname, "app")
/* 应用程序的起点入口。从这个起点开始,应用程序启动执行。
*/
entry:"./src/main.js",
output:{
filename:"bundle.js",
//
publicPath:"virtual"
},
module:{
rules:[
]
},
resolve:{
extensions:[".js",".vue",".css",".json"]
},
devServer:{
open: true,
/* When open is enabled, the dev server will open the browser.
使用默认浏览器打开服务
open: true
Usage via the CLI//命令行中使用
webpack-dev-server --open
If no browser is provided (as shown above), your default browser will be used. To specify a different browser, just pass its name:
//指定浏览器
webpack-dev-server --open 'Google Chrome */
/* 指定打开浏览器时要浏览的页面。
Specify a page to navigate to when opening the browser.
默认浏览的页面是webpack.config.js所在目录的index.html文件
*/
openPage: './public/index.html'
},
plugins:[
]
}
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue中使用TypeScript</title>
</head>
<body>
<script async src="../virtual/bundle.js"></script>
</body>
</html>
main.js:
alert(process.env.NODE_ENV);//development
欧克了,现在来启动服务:
启动服务, --progress可以将运行进度输出到控制台。
npx webpack-dev-server --progress
二、启动 JS 版 Vue
安装 Vue:
npm i -S vue
在 index.html 增加一个一行:
<div id="app"></div>
这时更改main.js文件:
import Vue from "vue";
new Vue({
el:"#app",
render:function(h){
return h("h1","TypeScript!")
}
})
打开网址查看,没有问题。但是如果把 main.js 改成这样:
import Vue from "vue";
new Vue({
el:"#app",
data:{
name: "TypeScript!"
},
template:"<h1>{{name}}</h1>"
})
会看到浏览器报错:
vue.runtime.esm.js:620 [Vue warn]: You are using the runtime-only build of Vue where the
template compiler is not available. Either pre-compile the templates into render functions,
or use the compiler-included build.
[Vue警告]:您正在使用Vue的仅运行时版本,而模板编译器不可用。可以将模板预编译为渲染函数,
也可以使用包含编译器的内部版本。
Vue 官网演示案例:
https://cn.vuejs.org/v2/guide/installation.html#%E6%9C%AF%E8%AF%AD
// 需要编译器
new Vue({
template: '<div>{{ hi }}</div>'
})
// 不需要编译器
new Vue({
render (h) {
return h('div', this.hi)
}
})
如果你使用 render(h)
渲染函数就不需要去 webpack 指定完整版了。现在我们去指定下 Vue 的版本,修改 webpack.config.js,需要注意的是:因为运行时版本相比完整版体积要小大约30%,所以应该尽可能使用这个版本。如果你仍然希望使用完整版,则需要在打包工具里配置一个别名:
module.exports = {
// ...
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js' // 用 webpack 1 时需用 'vue/dist/vue.common.js'
}
}
}
//https://cn.vuejs.org/v2/guide/installation.html
这个时候在 main.js 同级目录下创建 App.vue 文件,同时更改 main.js 文件的内容为:
import Vue from "vue";
import App from "./App";
new Vue({
el:"#app",
render:h=>h(App)
});
不过这时候我们还不能使用单文件组件,需要 loader 对应的 loader:
安装依赖:
npm i -D vue-loader vue-template-compiler
注意:
去 webpack.config.js 配置下loader:
// webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
module: {
rules: [
// ... 其它规则
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
},
plugins: [
// 请确保引入这个插件!
new VueLoaderPlugin()
]
}
你肯定好奇,vue-Loader 的配置和其它的 loader 怎么不太一样。除了通过一条规则将 vue-loader 应用到所有扩展名为 .vue 的文件上之外,还在 plugins 里使用了 VueLoaderPlugin 插件。这个插件是干啥的?
现在我们还没有安装处理 css 的 loader,这时我们对 App.vue 写上样式就会报错, App.vue 的内容:
<template>
<h1>哈哈</h1>
</template>
<style scoped>
h1{
color: rgb(55, 142, 230);
font-size: 25px;
text-align: center;
width: 200px;
line-height: 200px;
border: 10px solid #999;
border-radius: 5px;
}
</style>
安装处理样式的依赖:
npm i -D css-loader vue-style-loader
在去配置下 webpack :
module:{
rules:[
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
use: [
//顺序不能倒过来
'vue-style-loader',
'css-loader'
]
}
]
},
完成显示:
三、启动 TS 版 Vue
Vue 时自带 xx.d.ts
声明文件的,所以不用我们安装支持 TS 的第三方插件。
接着配置,安装插件并生成 ts.config.json
:
npm i -D ts-loader typescript
npx tsc --init
修改 webpack.config.js 的配置:
{
test: /\.ts?$/,
loader: "ts-loader",
options: {
// .vue文件必须加
appendTsSuffixTo: [/\.vue$/]
},
exclude:/node_modules/
}
App.vue 文件内容改为:
<template>
<h1>{{name}}</h1>
</template>
<script lang="ts">
//也执行tsx,也就是jsx语法
import Vue from "vue";
export default Vue.extend({
data(){
return {
name:"TypeScript!"
}
}
})
</script>
<style scoped>
h1{
color: rgb(55, 142, 230);
font-size: 25px;
text-align: center;
width: 200px;
line-height: 200px;
border: 10px solid #999;
border-radius: 5px;
}
</style>
//下面这种写法也行
<template>
<h1>{{name}}</h1>
</template>
<script lang="ts">
export default {
data(){
return {
name:123
}
}
}
</script>
<style scoped>
h1{
color: rgb(55, 142, 230);
font-size: 25px;
text-align: center;
width: 200px;
line-height: 200px;
border: 10px solid #999;
border-radius: 5px;
}
</style>
main.js 改为 main.ts 内容改成:
import Vue from "vue";
// 不能不加.vue后缀,不加会报错
import App from "./App.vue";
new Vue({
el:"#app",
render:h=>h(App)
});
这时启动服务会有个问题:
Cannot find module './App.vue'.
不能找到模块,由于 TypeScript 默认并不支持 *.vue 后缀的文件,所以在 vue 项目中引入的时候需要创建一个 vue-shims.d.ts 文件,意思是告诉 TypeScript 以 *.vue 为后缀的文件可以交给 vue 模块来处理 (真正的原因是导入的模块需要一个 Vueconstructor)。
而在代码中导入 *.vue 文件的时候,需要写上 .vue 后缀。原因是因为 TypeScript 默认只识别 *.ts 文件,不识别 *.vue 文件。
在 src 目录下新建 vue-shims.d.ts
:
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}
四、类组件
上面单文件组件 Vue 的写法固然是没问题,但是不能很好的去使用 ES6 类等语法,所以我们要改成类组件的形式。
安装依赖:
npm i -D vue-class-component
然后去修改下 App.vue 文件:
<template>
<div class="App">
<h1>{{count}}</h1>
<h3>{{name}}</h3>
<button @click="increment">加加</button>
<button @click="decrement">减减</button>
<h5>计算属性{{computed}}</h5>
<button @click="computed++">设置计算属性</button>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import Component from 'vue-class-component';
// Define the component in class-style
//@Component 装饰器使您的类成为Vue组件:
@Component({
// 对于所有其他选项,请将它们传递给装饰器函数:
// 如果没有可以省略
props:["name"],
components:{
}
})
export default class App extends Vue {
// Class properties will be component data
//类属性就是data中return 的数据
private count:number = 0;
// Methods will be component methods
//组件methods可以直接声明为类原型方法
private increment():void {
this.count++
}
private decrement():void {
this.count--
}
// 生命周期
private mounted():void{
console.log(this.count);
}
// 计算属性声明为类属性getter / setter:
get computed():number{
return this.count ** 2 ;
}
// A 'set' accessor cannot have a return type annotation.
// set访问器不能设置返回类型
set computed(value:number){
this.count = value++;
console.log(value);
}
}
</script>
<style scoped>
.App{
margin: 100px auto;
color: rgb(55, 142, 230);
font-size: 25px;
text-align: center;
width: 300px;
height: 400px;
border: 10px solid #999;
border-radius: 5px;
}
</style>
注意 main.ts 也被修改了:
import Vue from "vue";
// 不能不加.vue,会报错
import App from "./App.vue";
new Vue({
el:"#app",
components:{
App
},
template:"<App name='TypeScript' />"
});
又因为我们用到了装饰器,所以的更改下 tsconfig.js 文件,打开装饰器语法:
"experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
演示效果:
更多官网 API :https://class-component.vuejs.org/
五、Vue 装饰器
上面的案例我们使用了一个装饰器,挺好用的是不是,但是可以只有一个,如果想要更多可以参考官网自定义装饰器来给我们使用,我们当然不使用这种方式,我们使用插件:
npm i -D vue-property-decorator
看看官网提供了多少个装饰器:
There are several decorators and 1 function (Mixin):
@Prop
@PropSync
@Model
@Watch
@Provide
@Inject
@ProvideReactive
@InjectReactive
@Emit
@Ref
@Component (provided by vue-class-component)
Mixins (the helper function named mixins provided by vue-class-component)
注意这个插件是依赖vue-class-component
的。
我们来看几个最常用的,现在 App.vue 是 Children.vue 的父亲,main.ts 内容不变,来开始吧:
App.vue
<template>
<div class="App">
<h1>{{count}}</h1>
<h3>{{name}}</h3>
<Children @info="receive" @returnValue="returnValue"/>
</div>
</template>
<script lang="ts">
import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
import Children from './Children.vue';
// Define the component in class-style
//@Component 装饰器使您的类成为Vue组件:
@Component({
components:{
Children
},
watch:{
/* count(value){
console.log(value);
} */
count:{
handler:(value , oldValue)=>{
console.log(value,oldValue);
},
immediate:true,
deep: true
}
}
})
export default class App extends Vue {
// String开头字母大写
@Prop(String) name:string | undefined;
private count:number = 0;
private receive(val:number):void {
this.count = val;
}
private returnValue(val:number):void {
this.count = val;
}
@Watch("count" , { immediate: true, deep: true })
watch_count(val:any, oldVal:any) {
console.log(val,oldVal);
}
}
</script>
<style scoped>
.App{
margin: 100px auto;
color: rgb(55, 142, 230);
font-size: 25px;
text-align: center;
width: 300px;
height: 400px;
border: 10px solid #999;
border-radius: 5px;
}
</style>
Children.vue
<template>
<div class="chilren">
<p>我是子组件children</p>
<button @click="send">点我发射</button>
<button @click="returnValue">click me send</button>
</div>
</template>
<script lang="ts">
import { Vue, Component, Emit } from 'vue-property-decorator';
@Component
export default class Chilren extends Vue {
private val:number = 0;
@Emit("returnValue")
returnValue() {
this.val++;
return this.val;
}
private send():void{
this.val++;
this.$emit("info",this.val);
}
}
</script>
演示效果:
更多 API 参考官网:https://www.npmjs.com/package/vue-property-decorator
六、提升编译速度
现在项目编译一次需要时间为:
Time: 6236ms
随着项目变得越来越大,编译时间线性增加。这是因为在每次重建时,类型脚本的语义检查器必须检查所有文件。简单的解决方案是通过使用transfileOnly:true
选项来禁用它,但是这样做会使您没有类型检查,并且不会输出声明文件。
所以我们配置下 webpack.config.js 文件:
{
test: /\.tsx?$/,
use: [
{
loader: 'ts-loader',
options: {
transpileOnly: true
}
}
]
}
再次编译用时:
Time: 1659ms
快了不是一星半点。但是现在类型检查没了,这则么能够,这时我们使用 fork-ts-checker-webpack-plugin
另外开一个线程来进行类型检查,安装依赖:
npm install -D fork-ts-checker-webpack-plugin
//使用:
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
plugins:[
new ForkTsCheckerWebpackPlugin()
]
再次编译用时:
//无类型检查编译用时
Time: 1947ms
//加上类型检查用时
Time: 3284ms
就这也快了一半。
2020年2月15日 01点05分