webpack+vue+vue-router

webpack + vue + vue-router学习笔记

安装webpack

1
2
npm init
npm i -D webpack webpack-cli

建立代码目录

目录图片

使用webpack

终端

1
2
3
4
# {extry file}出填写入口文件的路径,本文中就是上述main.js的路径,
# {destination for bundled file}处填写打包文件的存放路径
# 填写路径的时候不用添加{}
webpack {entry file} -o {destination for bundled file}
  1. 命令:webpack app/main.js public/bundle.js
  2. 出错及更正:ERROR in multi ./hello.js bundle.js Module not found: Error: Can't resolve 'bundle.js,更正:webpack版本过高,原来的命令已经不适用了,更换打包命令:webpack app/main.js -o public/bundle.js

配置文件

根目录新建webpack.config.js,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const path = require('path');

module.exports = {
// 环境
mode: "development",
// 唯一入口
entry: path.resolve(__dirname, 'app/main.js'),
// 出口
output: {
// 打包后文件所在目录
path: path.resolve(__dirname, 'public'),
// 文件名
filename: 'bundle.js'
}
}

根目录运行webpack打包程序

npm配置

npm配置文件package.json中配置scripts可以运行相应命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"name": "vue-router-manual",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.16.5",
"webpack-command": "^0.4.1"
}
}

运行npm run build或者npm run-script build即可让webpack打包代码

搭建本地服务器

安装依赖:npm i -D webpack-dev-server
webpack配置:

1
2
3
4
5
6
7
8
9
// webpack本地服务器
devServer: {
contentBase: path.resolve(__dirname, 'public'), // 本地服务器所加载的页面所在目录
historyApiFallback: true, // 不跳转
inline: true, // 实时刷新
compress: true, // 是否压缩
host: '127.0.0.1',
port: 9000,
}

运行webpack-dev-server即可启动本地服务器

应用vue框架

vue代码

其中src中的main.js为入口文件。

1
2
3
4
5
6
7
8
9
10
11
// main.js
import Vue from 'vue';
// import Router from 'vue-router';
import App from './app.vue';

let root = document.createElement('div');
document.body.appendChild(root);

new Vue({
render: h => h(App)
}).$mount(root)

app.vue为单页面组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div class="test">{{msg}}</div>
</template>

<script>
export default {
data() {
return {
msg: " vue + vue-router + webpack"
};
}
};
</script>
<style>
.test {
color: coral;
}
</style>

安装loaders

webpack中安装并使用loader进行代码的打包

1
2
3
4
# npm一次性安装多个依赖模块,模块之间用空格隔开
npm i -D html-webpack-plugin
npm i -D vue vue-loader vue-template-compiler
npm i -D babel-core babel-loader babel-preset-es2015 style-loader css-loader url-loader file-loader

webpack配置完善为:

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// webpack.config.js
const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
// 环境
mode: "development",

// 生成Source Maps,使调试更容易
// eval-source-map只能在开发阶段使用
// devtools: 'eval-source-map',

// 唯一入口
entry: path.resolve(__dirname, 'src/main.js'),
// 出口
output: {
path: path.resolve(__dirname, 'dist'), // 打包后文件所在目录
filename: 'index.js' // 文件名
},
plugins: [
new htmlWebpackPlugin(),
new VueLoaderPlugin()
],

module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
}
},
{
test: /\.vue$/,
use: {
loader: 'vue-loader',
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(gif|jpg|jpeg|svg)$/,
use: {
loader: 'url-loader',
options: {
limit: 1024,
name: 'name.[hash:6].[ext]'
}
}
}
]
},

// webpack本地服务器
devServer: {
contentBase: path.resolve(__dirname, 'public'), // 本地服务器所加载的页面所在目录
historyApiFallback: true, // 不跳转
inline: true, // 实时刷新
compress: true, // 是否压缩
host: '127.0.0.1',
port: 9000,
}
}

错误及解决

  1. 选项配置错误
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Options Validation Error

options.module should match some schema in anyOf
options.module.rules[2] should match some schema in anyOf
options.module.rules[2].use should be string
options.module.rules[2].use should pass "instanceof" keyword validation
options.module.rules[2].use should match some schema in anyOf
options.module.rules[2].use should pass "instanceof" keyword validation
options.module.rules[2].use should match some schema in anyOf
options.module.rules[2].use should be object
options.module.rules[2].use should match some schema in anyOf
options.module.rules[2].use[0] should match some schema in anyOf
options.module.rules[2].use[0] should be string
options.module.rules[2].use[0] should pass "instanceof" keyword validation
options.module.rules[2].use[0] should match some schema in anyOf
options.module.rules[2].use[0].loader should be string
options.module.rules[2].use[0].loader should match some schema in anyOf

rules[2]配置错误,不能为数组,只能为字符串
解决方案:将原代码

1
2
3
4
5
6
7
8
{
test: /\.css$/,
use: [
{
loader: ['style-loader', 'css-loader']
}
]
},

更改为:

1
2
3
4
5
6
7
8
9
10
11
12
{
test: /\.css$/,
use: [
{
loader: 'style-loader',
// loader: ['style-loader', 'css-loader']
},
{
loader: 'css-loader',
}
]
},

或者更改为:

1
2
3
4
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},

2.vue-loader插件显性引入

1
2
3
Error1: Module Error (from ./node_modules/vue-loader/lib/index.js):
vue-loader was used without the corresponding plugin.
Make sure to include VueLoaderPlugin in your webpack config.

webpack4.X更新之后,需要显性引入vue-loader插件
解决方案:const VueLoaderPlugin = require('vue-loader/lib/plugin');详见vue-loader

3.vue-template-compiler需要作为单独的依赖

1
2
3
Error2: Module build failed (from ./node_modules/vue-loader/lib/index.js):
Error: [vue-loader] vue-template-compiler must be installed as a peer dependency,
or a compatible compiler implementation must be passed via options.

解决方案:npm i -D vue-template-compiler

应用vue-router

安装依赖:npm i -D vue-router

main.js

入口文件中,新建vue实例,参数中传入routercomponentstemplate

1
2
3
4
5
6
7
8
9
10
11
12
13
import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})

app.vue

使用 router-link 组件来导航。通过传入 to 属性指定链接,<router-link> 默认会被渲染成一个 <a> 标签。
<router-view/> 为路由出口,路由匹配到的组件将渲染在这里

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div>
<h1>你好</h1>
<router-link to="/helloworld">欢迎</router-link>
<router-view/>
</div>
</template>

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

router

router定义了跳转路由渲染的组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import Vue from 'vue';
import Router from 'vue-router';
import HelloWorld from '@/components/HelloWorld';
import Home from '@/components/Home';

Vue.use(Router);

export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/helloworld',
name: 'HelloWorld',
component: HelloWorld
}
]
})

问题解决

  1. vue使用template时更改vue使用模块
1
2
3
4
5
vue.runtime.esm.js:588 [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.

运行时构建不包含模板编译器,因此不支持 template 选项,只能用 render 选项,但即使使用运行时构建,在单文件组件中也依然可以写模板,因为单文件组件的模板会在构建时预编译为 render 函数。运行时构建比独立构建要轻量30%,只有 17.14 Kb min+gzip大小。就是说,如果我们想使用template,我们不能直接在客户端使用npm install之后的vue。

此时,再去看查vue模块,在webpack配置文件添加:

1
2
3
4
5
6
7
8
module.exports = {
// 省略...
resolve: {
alias: {
'vue': 'vue/dist/vue.js'
}
},
}

2.默认的代码目录使用@替换,webpack配置文件添加:

1
2
3
4
5
6
7
8
9
module.exports = {
// 省略...
resolve: {
alias: {
'vue': 'vue/dist/vue.js',
'@': path.resolve(__dirname,'src')
}
}
}

3.引入文件必须加后缀,否则报错,webpack配置文件添加:

1
2
3
4
5
6
7
8
9
10
11
module.exports = {
// 省略...
resolve: {
alias: {
'vue': 'vue/dist/vue.js',
'@': path.resolve(__dirname,'src'),
},
// 引入文件可不加后缀
extensions: ['.js', '.vue', '.json']
}
}

4.HTML

inject有四个值: true body head false

true 默认值,script标签位于html文件的 body 底部
body script标签位于html文件的 body 底部
head script标签位于html文件的 head
false 不插入生成的js文件,这个几乎不会用到的

1
2
3
4
5
6
7
8
const htmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
}),
],