一、背景
基础项目
基础项目是基于vue-cli+webpack-dev-middleware的项目。首先前端使用vue-cli搭建的环境(本教程略),然后使用express,配合webpack-dev-middleware发布前端文件。
server.js文件如下:
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const config = require('./config/index')
const app = express();
const webpackConfig = require('./build/webpack.server.conf.js');
const compiler = webpack(webpackConfig);
// Tell express to use the webpack-dev-middleware and use the webpack.config.js
// configuration file as a base.
app.use(webpackDevMiddleware(compiler, {
publicPath: webpackConfig.output.publicPath
}));
// Serve the files on port 3000.
const PORT = config.dev.port
app.listen(PORT, function () {
console.log('Example app listening on port ' + PORT + '!\n');
});
Github项目:Vue-webpackDevMiddleware基础项目
webpack-dev-middleware
An express-style development middleware for use with webpack bundles and allows for serving of the files emitted from webpack. This should be used for development only.
仅用于开发环境,通常与Express配合使用,通过webpack工具可以对前端文件进行打包,配合webpack-hot-middleware可实现热加载。
Github项目:webpack-dev-middleware
二、开始改造
安装一些依赖
为了支持TypeScript,需要增加一些依赖:
- style-loader 1.0.0
- ts-loader 6.0.4
- tslint 5.18.0
- tslint-config-standard 8.0.1
- tslint-loader 3.5.4
- typescript 3.2.2
- vue-class-component 7.1.0
- vue-property-decorator 8.1.1
注意,安装这些依赖要指定版本,不然不同版本的插件可能会不兼容。在package.json中,也把依赖的版本^去掉,防止不兼容。
除了新增了一些依赖,同时某些依赖的版本也有变化,建议直接拷贝下面的package.json文件,然后npm install安装。
{
"name": "Vue-webpackDevMiddleware",
"version": "1.0.0",
"description": "A Vue project based on express. Use Webpack-dev-middleware to build a dev enviroment.",
"author": "David-Shi-1989 <287841605@qq.com>",
"private": true,
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "webpack-dev-server --open",
"server": "node server.js",
"unit": "jest --config test/unit/jest.conf.js --coverage",
"e2e": "node test/e2e/runner.js",
"test": "npm run unit && npm run e2e",
"lint": "eslint --ext .js,.vue src test/unit test/e2e/specs",
"build": "node build/build.js"
},
"dependencies": {
"vue": "2.5.16",
"vue-router": "3.0.1"
},
"devDependencies": {
"autoprefixer": "7.2.6",
"babel-core": "6.26.3",
"babel-eslint": "8.2.3",
"babel-helper-vue-jsx-merge-props": "2.0.3",
"babel-jest": "21.2.0",
"babel-loader": "7.1.4",
"babel-plugin-dynamic-import-node": "1.2.0",
"babel-plugin-syntax-jsx": "6.18.0",
"babel-plugin-transform-es2015-modules-commonjs": "6.26.2",
"babel-plugin-transform-runtime": "6.23.0",
"babel-plugin-transform-vue-jsx": "3.7.0",
"babel-preset-env": "1.6.1",
"babel-preset-stage-2": "6.24.1",
"babel-register": "6.26.0",
"chalk": "2.4.1",
"clean-webpack-plugin": "0.1.19",
"copy-webpack-plugin": "4.5.1",
"cross-spawn": "5.1.0",
"css-loader": "0.28.11",
"eslint": "4.19.1",
"eslint-config-standard": "10.2.1",
"eslint-friendly-formatter": "3.0.0",
"eslint-loader": "2.1.0",
"eslint-plugin-import": "2.11.0",
"eslint-plugin-node": "5.2.1",
"eslint-plugin-promise": "3.7.0",
"eslint-plugin-standard": "3.1.0",
"eslint-plugin-vue": "4.5.0",
"express": "4.16.3",
"extract-text-webpack-plugin": "4.0.0-beta.0",
"file-loader": "1.1.11",
"font-awesome": "4.7.0",
"friendly-errors-webpack-plugin": "1.7.0",
"html-webpack-plugin": "3.2.0",
"jest": "22.4.3",
"jest-serializer-vue": "0.3.0",
"nightwatch": "0.9.21",
"node-notifier": "5.2.1",
"optimize-css-assets-webpack-plugin": "3.2.0",
"ora": "1.4.0",
"portfinder": "1.0.13",
"postcss-import": "11.1.0",
"postcss-loader": "2.1.4",
"postcss-url": "7.3.2",
"rimraf": "2.6.2",
"selenium-server": "3.11.0",
"semver": "5.5.0",
"shelljs": "0.7.8",
"style-loader": "1.0.0",
"ts-loader": "6.0.4",
"tslint": "5.18.0",
"tslint-config-standard": "8.0.1",
"tslint-loader": "3.5.4",
"typescript": "3.2.2",
"uglifyjs-webpack-plugin": "1.2.5",
"url-loader": "0.5.9",
"vue-class-component": "7.1.0",
"vue-jest": "1.4.0",
"vue-loader": "14.2.2",
"vue-property-decorator": "8.1.1",
"vue-style-loader": "3.1.2",
"vue-template-compiler": "2.5.16",
"webpack": "4.0.0",
"webpack-bundle-analyzer": "2.11.1",
"webpack-cli": "2.1.2",
"webpack-dev-middleware": "2.0.6",
"webpack-dev-server": "3.1.0",
"webpack-merge": "4.1.2"
},
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}
修改webpack配置文件
与vue-cli搭出来的纯前端不同,我们这里使用express发布,webpack配置文件在build\webpack.server.conf.js
。需要修改以下几点:
1. entry入口文件
入口文件由main.js
改为main.ts
entry: {
app: './src/main.ts'
}
同时把src\main.js
重命名为main.ts
,文件内容如下:
// The Vue build version to load with the import command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from '@/App.vue'
import router from '@/router/index'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
router,
render: (h) => h(App)
}).$mount('#app')
2. resolve.extensions增加ts
resolve: {
extensions: ['.ts', '.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('./src'),
}
}
3. module.rules增加ts的规则
{
test: /\.ts$/,
exclude: /node_modules/,
enforce: 'pre',
loader: 'tslint-loader'
},
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/\.vue$/],
}
}
4. 新建文件tsconfig.json
{
"include": [
"src/**/*"
],
"exclude": [
"node_modules"
],
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"allowJs": true,
"module": "esnext",
"target": "es5",
"moduleResolution": "node",
"isolatedModules": true,
"lib": [
"dom",
"es5",
"es2015.promise"
],
"sourceMap": true,
"pretty": true
}
}
5. 新建文件src\vue-shims.d.ts
declare module "*.vue" {
import Vue from "vue";
export default Vue;
}
6. 新建文件tslint.json
{
"extends": "tslint-config-standard",
"globals": {
"require": true
}
}
此时到这里,运行server.js(node server.js),页面可以正常打开。
修改vue文件
此时项目已经支持ts了,接下来修改vue文件,将js代码改为ts代码。
1. 修改App.vue
由于实现等原因,ts代码放进vue文件不生效,所以把ts代码提出来,放在单独的ts文件里,在vue文件中引入。
App.vue:
<template>
<div id="app">
<img src="./assets/logo.png">
<router-view/>
</div>
</template>
<script lang="ts" src="./App.ts"></script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
App.ts:
import Vue from 'vue'
import { Component } from 'vue-property-decorator'
@Component({
})
export default class App extends Vue{
created () {
console.log(`App created`)
}
}
2. 新增组件person-info.vue
person-info.vue:
<template>
<p>
<span>{{name}}</span>
<span>{{age}}</span>
<span>{{nickName}}</span>
<span>{{timestamp}}</span>
</p>
</template>
<script lang="ts" src="./person-info.ts">
</script>
<style scoped>
</style>
person-info.ts:
import { Vue, Component, Prop } from 'vue-property-decorator'
@Component({})
export default class HelloWorld extends Vue {
@Prop(String) name: string | undefined
@Prop(Number) age: number | undefined
@Prop(String) nickName: string | undefined
@Prop(String) timestamp: string
}
3. 修改HelloWorld.vue
HelloWorld.vue引入person-info组件:
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>Essential Links</h2>
<ul>
<li>
<a
href="https://vuejs.org"
target="_blank"
>
Core Docs
</a>
</li>
<li>
<a
href="https://forum.vuejs.org"
target="_blank"
>
Forum
</a>
</li>
<li>
<a
href="https://chat.vuejs.org"
target="_blank"
>
Community Chat
</a>
</li>
<li>
<a
href="https://twitter.com/vuejs"
target="_blank"
>
Twitter
</a>
</li>
<br>
<li>
<a
href="http://vuejs-templates.github.io/webpack/"
target="_blank"
>
Docs for This Template
</a>
</li>
</ul>
<h2>Ecosystem</h2>
<ul>
<li>
<a
href="http://router.vuejs.org/"
target="_blank"
>
vue-router
</a>
</li>
<li>
<a
href="http://vuex.vuejs.org/"
target="_blank"
>
vuex
</a>
</li>
<li>
<a
href="http://vue-loader.vuejs.org/"
target="_blank"
>
vue-loader
</a>
</li>
<li>
<a
href="https://github.com/vuejs/awesome-vue"
target="_blank"
>
awesome-vue
</a>
</li>
</ul>
<personInfo :name="name" :age="age" nickName="sdas" :timestamp="ts"></personInfo>
</div>
</template>
<script lang="ts" src="./HelloWorld.ts"></script>
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
HelloWorld.ts文件:
import { Vue, Component } from 'vue-property-decorator'
import personInfo from './person-info.vue'
@Component({
components: {
personInfo
}
})
export default class HelloWorld extends Vue {
msg: string = 'Welcome Typescript + Vue'
ts: string = ''
name: string = 'david'
age: number = 29
created () {
this.ts = String(Date.now().valueOf())
console.log(this.ts)
}
}
三、结束
运行效果
此时,运行出来的页面如下:
总结
1. 改进
-
解决告警mode
WARNING in configuration. The 'mode' option has not been set. Set 'mode' option to 'development' or 'production' to enable defaults for this environment.
解决办法:在build\webpack.server.conf.js
中增加mode如下:// ... module.exports = { entry: { app: './src/main.ts' }, mode: 'development', // ...
- 告警
Warning: The 'await-promise' rule requires type information.等告警
解决办法: 待解决 - ts代码写入vue文件中
解决办法: 待解决
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。