github可下源码

先创个空白文件夹:

1
2
mkdir learn-vue
cd learn-vue

新建一个页面index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>learn-vue</title>
</head>
<body>
<div id="app">
<p>{{ message }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
}
})
</script>
</body>
</html>

这是我们在学习vue的时候会看到的最原始的代码。那我们如何对其进行改造呢。

根目录建立package.json文件,可以手动也可以命令行

1
npm init -y

去掉冗余,简单一点

1
2
3
4
{
"name": "learn-vue",
"version": "1.0.0"
}

然后安装webpack 已安装可以忽略

1
npm install --save-dev webpack webpack-cli

会发现目录中增加了node_modules

Alt text

node_modules其实就类似于maven,这里有个有趣的知乎回答

package.json中变成这样了:

1
2
3
4
5
6
7
8
{
"name": "learn-vue",
"version": "1.0.0",
"devDependencies": {
"webpack": "^4.16.5",
"webpack-cli": "^3.1.0"
}
}
webpack是一个js打包工具,使用webpack你可以在一个js文件中使用 import 或者 require 来引用另外一个js文件中定义的组件。不消说,这样你就可以把js组件分文件存放了。 通过webpack就可以把多个js文件打包成一个js文件。使用了webpack就可以使用import语句来导入别的js文件,这样做有两个好处
  • 不需要将公共库的js引用写到页面上来了,比如vue的引用就不需要写到index.html页面上了。

  • 你可以将你的所有js脚本可以按模块来分文件存放了

vue+webpack后发生了第一次转变:

1
npm install npm -g

package.json 变为:

1
2
3
4
5
6
7
8
9
10
11
{
"name": "learn-vue",
"version": "1.0.0",
"devDependencies": {
"webpack": "^4.16.5",
"webpack-cli": "^3.1.0",
},
"dependencies": {
"vue": "^2.5.17",
}
}

根目录新建src文件夹,并建立main.js

1
2
3
4
5
6
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
}
})

index.html中的script语句替换成:

1
<script src="src/main.js"></script>

并把这句话去掉

1
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
打开网页还是有hello world的。

注意了,接下来就要开始用webpack了:

修改main.js脚本,增加这个开头:

1
2
import Vue from 'vue/dist/vue.js'

根目录新建文件webpack.config.js:

1
2
3
4
5
6
7
8
9
10
 var path = require('path');

module.exports = {
mode: 'development',
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
};

简单的讲解一下这个webpack.config.js

  • mode: 主要用到的模式有production和development。开发时使用development,所以我们现在用development,其实你就算用production对我们的例子也没什么影响。

  • entry: 我嫩之前不是说过使用了webpack之后就可以引用import来导入别的js文件么?那么你可以想象一下,你项目中的js可以构成一个引用树。这个引用树总要有一个树根的,这个树根是不会被任何js所引用的,所有引用最后都可以回溯到它。这里的entry就是webpack的js引用树树根文件

  • output:定义了打包后文件要存放的路径和文件名

    index.html中main.js改成:

    1
    2
    <script src="dist/bundle.js"></script>

根目录新建一个dist文件夹作为output的目录。

1
mkdir dist

npx webpack后我们能够看到Hello Vue.js

SFC结构:

src下新建components目录,新建HelloVue.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<p>{{ message }}</p>
</template>
<script>
export default {
name: 'HelloVue',
data: function() {
return {
message: 'Hello Vue.js!'
}
}
}
</script>

src下新建App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<HelloVue/>
</template>

<script>
import HelloVue from './components/HelloVue.vue'

export default {
name: 'App',
components: {
HelloVue
}
}
</script>

main.js改为:

1
2
3
4
5
6
7
8
import Vue from 'vue/dist/vue.js'
import App from './App.vue'

new Vue({
el: '#app',
components: { App },
template: "<App/>"
})

index.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>learn-vue</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

原理:

1
2
3
4
5
6
index.html是不可能直接使用.vue文件的,
因为浏览器不知道.vue文件是什么。
所以App.vue是通过被某个js调用,
从而被index.html所感知的。
所以它们之间必须要有一个js文件作为连接。
我们使用之前建立的main.js来引用App.vue

使用template属性来定义模板 , 使用name属性来注册组件。我们在模板中使用了Hello.vue组件

除此之外,webpack是不认识vue的,所以要添加解析器:

1
npm install --save-dev vue-loader vue-template-compiler

并在webpack.config.js中添加:

1
const { VueLoaderPlugin } = require('vue-loader')
1
2
3
plugins: [
new VueLoaderPlugin()
]
1
2
3
4
5
6
7
8
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
}
]
},

最终为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var path = require('path');
const { VueLoaderPlugin } = require('vue-loader')

module.exports = {
mode: 'development',
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
}
]
},
plugins: [
new VueLoaderPlugin()
]
};

使用html-webpack-plugin自动插入脚本

安装:

1
npm install --save-dev html-webpack-plugin

webpack.config.js 中添加:

1
const HtmlWebpackPlugin = require('html-webpack-plugin')
1
2
3
4
5
6
7
8
9
plugins: [
new VueLoaderPlugin(),
// 以下是HtmlWebpackPlugin的配置
new HtmlWebpackPlugin({
template: 'index.html',
filename: './index.html', // 输出文件【注意:这里的根路径是module.exports.output.path】
hash: true
})
]

到这里就已经可以正常运行了。

那么如何实现热部署呢?

安装webpack-dev-server,它可以配置不同的模式来自动更新页面

1
npm install --save-dev  webpack-dev-server

并在package.json中添加:

1
2
3
4
"scripts": {
"dev": "webpack-dev-server --inline --progress --config webpack.config.js",
"start": "npm run dev",
},

npm start/npm run dev就可以运行了,并且更改后会自动更新。

js改为ts:(typescript)

安装:

1
2
yarn add vue-class-component vue-property-decorator
yarn add ts-loader typescript --dev

webconfig.config.js中添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    resolve: {
extensions: ['.js', '.vue', '.json', '.ts'],
alias: {
'@': path.resolve(__dirname, '..', 'src'),
}
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/\.vue$/],
}
},
{
test: /\.vue$/,
loader: 'vue-loader',
}
]
},

根目录添加

tsconfig.json:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"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
}
}

在 ./src 目录创建 vue-shim.d.ts 文件,让 ts 识别 .vue 文件:

1
2
3
4
5
// vue-shim.d.ts
declare module "*.vue" {
import Vue from "vue";
export default Vue;
}

main.js改为main.ts,

改造之后的 ts 文件不会识别 .vue 文件,所以在引入 .vue 文件的时候,需要手动添加 .vue 后缀

原文作者

webpack.config.js中的main.js也改为main.ts!

App.vue改造为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div id="app">
<hello1/>
</div>
</template>

<script lang="ts">
import Vue from 'vue'
import hello from './components/HelloVue.vue'
import Component from 'vue-class-component'
@Component({
components: {
'hello1': hello
}
})
export default class App extends Vue{
}
</script>

HelloVue.vue改造为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<p>{{message}}</p>
</template>


<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class App extends Vue {
message="hello World!"
}
</script>

webpack.config.js最终改造为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

var path = require('path');

const { VueLoaderPlugin } = require('vue-loader')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
mode: 'development',
entry: './src/main.ts',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
resolve: {
extensions: ['.js', '.vue', '.json', '.ts'],
alias: {
'@': path.resolve(__dirname, '..', 'src'),
}
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/\.vue$/],
}
},
{
test: /\.vue$/,
loader: 'vue-loader',
}
]
},
plugins: [
new VueLoaderPlugin(),

new HtmlWebpackPlugin({
template: 'index.html',
filename: './index.html',
hash: true
})
]
};

执行命令:

1
npm install

1
npm start

运行得到hello world!

小小demo