使用 Laravel Mix 布局更合理的 Vue 前后端分离项目结构

本文以 ThinkPHP、Vue 为例,理应(未经验证)适用于 React、Angular 或其他前端项目,Java、Python 或其他后端项目。

目前网络上流传了一些糟糕的 Vue 前后端分离实践,前端与后端各自独立成一个项目,作为全栈开发的工作流程来说非常不合适。

这是因为 Vue Cli 提供的项目结构不易于嵌入其他框架内:

  • 与现代 PHP 框架重叠的 public 目录
  • Watch / Hot Reload 需要使用 vue serve 访问而不是通过 Web 服务器
  • outputDir 强制清空 dist 构建目录

    • 设为 dist 目录,需要二次拷贝到 public 目录
    • 设为 public 目录会将 ThinkPHP 的 index.php 等文件清除,--no-clean 参数不适合长期使用
  • filenameHashing 不会生成 manifest 文件(需要通过 Webpack 配置)

这对于习惯了 Laravel 舒适工作流程的我来说很难接受,而解决这些问题需要大量时间。

Laravel Mix 介绍

Laravel Mix 是对于 Webpack 的优雅包装,提供了大量易于使用的实用功能。最重要的是可以无侵入式地与其他后端项目一同构建前端工作流程,只需要在后端项目内添加:

  • src(前端项目目录,可任意自定义路径与名称)
  • package.json
  • webpack.mix.js

而不需要为前端项目提供一个独立的文件夹。

安装

首先初始化 NPM 项目,为了便于使用 NPM Scripts,需要一同安装 cross-env

npm init -y

npm install laravel-mix cross-env --save-dev

然后在 package.json 中配置 NPM Scripts:

"scripts": {
    "dev": "npm run development",
    "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
    "watch": "npm run development -- --watch",
    "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
    "prod": "npm run production",
    "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
}

Laravel Mix 提供了示例配置文件,将它拷贝到当前目录:

cp node_modules/laravel-mix/setup/webpack.mix.js ./

你也可以重新编写配置文件 webpack.mix.js:

const mix = require("laravel-mix")

mix.js("src/app.js", "public/js")
    .sass("src/app.scss", "public/css")

使用 Manifest 版本号

ThinkPHP 中没有实现 mix() 辅助函数,参考 Laravel 实现 Mix 辅助函数源码(Illuminate/Foundation/Mix.php),可以实现一版简易的 mix 辅助函数。

$manifest = json_decode(file_get_contents(public_path() . '/mix-manifest.json'), true);

如果只有单入口,可以使用模板变量赋值,避免实现 helper 辅助函数。

return view('index', ['manifest' => $manifest]);

在 View 中引用动态版本号:

<link rel="stylesheet" type="text/css" href="<?= $manifest['/css/app.css'] ?>">
<script type="text/javascript" src="<?= $manifest['/js/app.js'] ?>"></script>
发表评论