前言:
在大型富交互的项目中,前后端分离的设计越来越受到重视。
为了方便前后端同学在一个项目中进行开发,我这边的项目搭建并没有使用laravel-mix(领导说不要使用不熟悉的东西),而是直接使用vue+webpack进行搭建。
背景:
- resources
- views 模板文件
- index 入口文件放置的文件夹
- vue vue全部文件,blade的模板文件
- build 构建参数和脚本
- src 源代码
- tpl 需要构建给laravel blade的模板文件
- config 构建环境参数
- public
- v webpack的构建内容全部在放在这里,当然这个是要配置的
坑们:
主要的坑都来自开发环境
坑一:页面入口问题。
在vue默认的项目中,代码会自动生成一个index.html作为首页。而在laravel中使用的blade模板。我首先想了两个方案。
1、使用插件 assets-webpack-plugin 生成assets.json 文件,然后由php动态解析到模板中。
2、直接由webpack构建系统生成blade模板
坑一解决:
第一种做法操作简单,不过每次都要解析assets.json文件。
第二种做法不需要解析文件,但是需要让vue的构建系统侵入(或叫操作) laravel的文件夹(views中添加文件)。
不过这两种方法在dev模式下都有一个问题,热更新模式下都不会生成文件。不管是assets.json 还是 index.blade.php(坑二解决)。
坑二:热更新的情况话不会生成index.blade.php文件。
坑二解决:我在 build/dev-server.js 中添加了强制复制 resouces/vue/tpl/index_dev.blade.php 到 resouces/views/index/index.blade.php。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| //build/dev-server.js 文件
...
var opn = require('opn')
var path = require('path')
var express = require('express')
var webpack = require('webpack')
var proxyMiddleware = require('http-proxy-middleware')
var webpackConfig = require('./webpack.dev.conf')
// copy函数会把模板文件复制到views中供laravel解析
var fs = require('fs');
function copy(src, dst) {
fs.createReadStream(src).pipe(fs.createWriteStream(dst));
}
// 测试的时候应该把测试用的index文件复制到真正的文件中
copy(__dirname + '/../tpl/index_dev.blade.php', __dirname + '/../../views/index/index.blade.php');
//本文附录中会带index_dev.blade.php文件内容
...
|
当然,在npm run build 的时候也得构建正常的index.blade.php文件到views中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| // build/webpack.prod.conf.js 文件
...
new HtmlWebpackPlugin({
filename: resolve('../../views/index/index.blade.php'),
template: resolve('./tpl/index_tpl.blade.php'), //webpack 会自动将脚本注入body尾部,为了方便语法,模板文件的文件后缀也用了blade.php
//本文附录中会带index_tpl.blade.php文件内容
inject: true,
minify: {
removeComments: true,
collapseWhitespace: false, //注意不要设置为true ,会将模板内格式删除,不利于blade解析
removeAttributeQuotes: true
},
chunksSortMode: 'dependency'
}),
...
|
坑三:热更新的地址指向问题。
因为laravel开发都是使用nginx或者valet 所以laravel使用的是127.0.0.1:80端口或者 project_dir.dev 域名,而热更新使用肯定是127.0.0.1:8080作为端口(端口可设置)所以造成了热资源无法读取
坑三解决:
build/dev-client.js 设定绝对路径
1
2
3
4
5
6
| // build/dev-client.js
var hotClient = require('webpack-hot-middleware/client?noInfo=false&reload=true')
// 改为
var hotClient = require('webpack-hot-middleware/client?path=http://127.0.0.1:8080/__webpack_hmr&noInfo=false&reload=true')
|
热更新会自动使用 / 作为根地址,所以要将webpack的 publicPath地址设置为绝对路径。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // webpack.base.conf.js 原
...
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
...
// 改为
...
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: 'http://127.0.0.1:8080/' // 这里也可修改 config.dev.assetsPublicPath 对应的内容
...
|
坑四:热更新跨域问题。
坑四解决:
在build/dev-server.js中设置跨域头
1
2
3
4
5
6
7
8
9
10
11
| // build/dev-server.js
// 在生成app变量后
// 设置全局跨域
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});
|
总结:
写了这么多,发现全都是热更新的问题= =,不过搞定以上几点,对于laravel + vue 的前后端分离开发就很方便了,前端依然用自己的方式去开发,后端只提供一个入口index,剩下的都走API。
附录:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| // index_dev.blade.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>首页</title>
</head>
<body>
<div id="main-app"></div>
<!-- built files will be auto injected -->
<script src="http://127.0.0.1:8080/vendor.js"></script>
<script src="http://127.0.0.1:8080/app.js"></script>
<!-- 有新的内容请手动填写 -->
</body>
</html>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // index_tpl.blade.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>首页</title>
</head>
<body>
<div id="main-app"></div>
<!-- built files will be auto injected -->
<!-- 新内容将自动注入 -->
</body>
</html>
|