【爬坑】在laravel中使用vue(非laravel-mix)

【爬坑】在laravel中使用vue(非laravel-mix)

laravel_vue.jpg

前言:

在大型富交互的项目中,前后端分离的设计越来越受到重视。

为了方便前后端同学在一个项目中进行开发,我这边的项目搭建并没有使用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>
Licensed under CC BY-NC-SA 4.0