【问题标题】:Vue.js : Best way to implement MPA(Multi page app) in laravelVue.js:在 laravel 中实现 MPA(多页面应用程序)的最佳方式
【发布时间】:2018-06-22 18:16:16
【问题描述】:

我已经四处寻找了很长一段时间,但没有得到任何召集。

在 laravel 中实现 Vue MPA 架构的最佳方法和实践是什么。

搜索了很多。但是没有任何东西可以让你有一个清晰的想法。您的回答会很有帮助,请简明扼要。

回答这个问题也很有帮助:

  • 仅使用 laravel 作为数据 API 是否是个好主意,并保留 Vue 与 laravel 分开?
  • 实现 SPA 和 MPA 混合的最佳方法。

【问题讨论】:

    标签: javascript laravel design-patterns vue.js multipage


    【解决方案1】:

    我已经使用过的一些选项:

    使用 Laravel 渲染“主视图”+连接 vue.js 应用。

    基本上,laravel 会渲染 Vue 应用程序,每个请求都通过一个 API。

    1. 易于设置
    2. 身份验证 + 用户验证更容易(您可以为此使用 laravel 会话管理器 - 无需构建/使用令牌或其他任何东西。“无需担心您的应用程序状态”。)
    3. 轻松“断开”与 Laravel 的“断开连接” - 如果您将来选择解耦 SPA 应用程序。

    仅将 laravel(或 lumen)用作 API,并在另一台服务器上呈现 SPA。

    这可能需要更多时间,因为您需要设置额外的服务器、准备跨域等。

    1. 也易于设置,但可能比选项 #1 花费更多时间
    2. 您需要为用户验证/状态管理等创建一些东西。
    3. 如果您将来决定使用“仅一个应用程序”,则可以轻松放入 laravel。
    4. 可以更容易维护/扩展(如果你有一个前端团队,他们不需要担心 laravel - 你的“laravel 团队”也是如此,他们“不需要担心”前端)

    Laravel + Vue =“一个应用程序”

    您可以使用 Laravel 为页面中的组件/元素渲染所有视图 + vuejs。

    1. 易于设置。你有 laravel + vuejs,它们已经准备好一起使用了。 https://laravel.com/docs/5.5/frontend#writing-vue-components
    2. 解耦没那么容易。在这种情况下,您需要为 vue.js 创建相同的视图。这可能需要一些时间。
    3. 这是“传统的 Web 开发”(在我看来)。如果我今天必须开始这样的项目,我不会在 Vue.js 中创建所有页面 + 在 Laravel(控制器 + 新路由)中创建一些东西来呈现这个视图。如果您这样做(再次-我的观点),那只是额外的工作。如果您担心 SEO,可以选择“后备”/额外选项。

    --

    所有选项都是可测试的 + 可扩展的。

    这还取决于你如何开始(我应该担心我将来如何解耦应用程序吗?Laravel + Vue 会永远好?),你的团队将如何工作(前端团队真的需要设置 laravel 还是只需要关心前端代码?)等等

    不确定我是否回答了您的问题,如果没有,请发表评论。

    【讨论】:

    • 很好的答案,写得很好,但是如何再次实现 MPA,如果你看第一个答案,那有点回答了。请稍微解释一下技术方面。谢谢
    • 你能解释一下我的用例是第一个选项更好还是第三个选项更好?我正在重建 SaaS 遗留应用程序。当前系统使用 cakephp 和 jQuery(重度 jQuery 依赖),我非常擅长 laravel,但更熟悉 Vue.js
    【解决方案2】:

    您没有发现任何明确的内容,因为除了“您的理解和项目需求感觉正确的内容”之外,没有什么可谈的。如果您发现自己非常不确定,请随意潜入做任何对您有意义的事情,然后在获得更多经验时重新调整结构。

    另外,阅读有关系统架构的书籍,这些会有很大帮助。


    仅使用 laravel 作为数据 API 并保持 Vue 与 Laravel 分开是个好主意吗?

    我假设您的意思是 SPA?老实说,如果您的应用程序很小,那么我认为这很好。

    如果是 SPA,大型应用程序往往难以维护。

    阅读:https://medium.com/@NeotericEU/single-page-application-vs-multiple-page-application-2591588efe58

    如果你最终使用 Laravel 作为 API 端点,那么请使用它的精简版 Lumen,因为它没有 Blade 和其他一些东西。 Lumen 是精简版以充当 API 端点。


    实现 SPA 和 MPA 混合的最佳方法。

    根据我尝试构建 4 个以上混合项目的经验,这是我发现的最佳结构:

    我的示例将是关于保存“帖子”的应用程序。

    1。使用存储库设计模式。

    这将为您在维护代码和维护代码中的 DRY(不要重复自己)概念时省去很多麻烦。

    • 创建目录App\Repositories\

    创建一个新类PostsRepository。这个是与数据库通信的,包含大部分逻辑。

    • 创建目录App\Services\

    创建一个新类PostsService。这个将在其构造函数中包含PostsRepository

    服务类将是一种从 Web 控制器或 API 控制器获取用户输入的处理。

    <?php
    
    namespace App\Service;
    
    use App\Repositories\PostsRepository;
    
    class PostsService;
    {
        protected $repository;
    
        public function __construct(PostsRepository $repository)
        {
            $this->repository = $repository;
        }
    }
    
    • 将 Web 控制器和 API 控制器分开。

    对于网络控制器,您可以像往常一样创建控制器:

    php artisan make:controller PostsController

    对于 API 控制器,您可以在 Api 文件夹中创建控制器。

    php artisan make:controller Api\PostsController

    最后一个命令将创建目录 App\Http\Controllers\Api 并将控制器放置在其中。

    回顾

    现在我们有不同的控制器来返回适合起点(web / api)的结果。

    我们有服务,两个(web / api)控制器都发送他们的数据进行验证(并让存储库采取行动)。

    例子:

    <?php
    
    namespace App\Http\Controllers;
    
    use App\Service\PostsService;
    
    class PostsController extends Controller
    {
      protected $service;
    
      public function __construct(PostsService $service)
      {
          $this->service = $service;
      }
    
      public function index()
      {
         /**
         * Instead of returning a Blade view and
         * sending the data to it like:
         *
         *          $posts = $this->service->all();
         *          return views('posts.index', compact('posts'));
         *
         * We go ahead and just return the boilerplate of 
         * our posts page (Blade).
         */
         return view('posts.index');
      }
    }
    

    ...

    <?php
    
    namespace App\Http\Controllers\Api;
    
    use App\Service\PostsService;
    
    class PostsController extends Controller
    {
      protected $service;
    
      public function __construct(PostsService $service)
      {
          $this->service = $service;
      }
    
      /**
      * Returns all posts.
      *
      * A vue component calls this action via a route.
      */
      public function index()
      {
         $posts = $this->service->all();
    
         return $posts;
      }
    
      /**
      * Notice we don't have a store() in our
      * Web controller.
      */
      public function store()
      {
         return $this->service->store();
      }
    }
    

    ...

    <?php
    
    namespace App\Services;
    
    use App\Repositories\PostsRepository;
    
    class PostsService extends Controller
    {
      protected $repository;
    
      public function __construct(PostsRepository $repository)
      {
          $this->repository = $repository;
      }
    
      public function all()
      {
         $posts = $this->repository->all();
    
         return $posts;
      }
    
      public function store()
      {
         $request = request()->except('_token');
    
         $this->validation($request)->validate();
    
         return $this->repository->store($request);
      }
    
      public function validation(array $data)
      {
          return Validator::make($data, [
              'content' => 'required|string|max:255',
              //
          ]);
      }
    }
    

    在我们的 PostsRepository 中,我们实际上调用了保存数据的方法。例如。 Post::insert($request);.

    2。专门的 API 组

    Route::prefix('api/v1')->middleware('auth')->group(function() {
    
        Route::post('posts/store', 'Api\PostsController@store')->name('api.posts.store');
    
    });
    

    在进行 phpunit 测试时,为 API 路由提供 -&gt;name() 会有所帮助。

    3。刀片视图

    这些应该被简单地剥离。

    views/posts/index.blade.php:

    @extends('layouts.app', ['title' => trans('words.posts')])
    
    @section('content')
      <!-- Your usual grid columns and stuff -->
      <div class="columns">
         <div class="column is-6">
             <!-- This comp. can have a modal included. -->
             <new-post-button></new-post-button>
         <div class="column is-6">
              <posts-index-page></posts-index-page>
         </div>
      </div>
    @endsection
    

    4。 Vue 结构。

    https://github.com/pablohpsilva/vuejs-component-style-guide

    因此,这些 Vue 组件可能存在于 resources/assets/js/components/posts/ 中,而在 /posts/ 内部,我会有标题为 IndexPageCreateModalEditModal 的文件夹,每个文件夹都有其 .vueREADME.md

    我会在index.blade.php 中使用&lt;posts-index-page&gt;,并在需要时随时添加&lt;post-create-modal&gt;&lt;edit-post-modal&gt;

    所有的 vue 组件都将使用我们在 Routes 文件中指定的 API 端点。

    【讨论】:

    • README.md 是干什么用的?
    • @commonsense README.md 是编写自己的 README.md tbh。您指定组件的用途、它所采用的道具及其种类(如果有的话)、如何使用它……等等。几乎为了自己的利益而维护自己的代码。
    • @Spacemudd 好多了。
    • 编辑/更新功能怎么样?您如何在 组件上传递 post_id 参数(假设您没有使用 Modal)。你要接受来自 App\Http\Controllers\PostController@edit 的组件的 :post_id 属性吗?
    • @ChrisLandeza 如果&lt;edit-post-page&gt; 很简单,那么是的,我会传递一个:post_id 道具。然而,在多个组件需要:post_id 的更复杂的情况下,我更喜欢使用 Vuex 来管理我的状态,我可以让我的状态的post_id 可以从任何组件访问而无需传递道具。
    猜你喜欢
    • 2020-10-22
    • 2021-03-19
    • 2010-11-26
    • 2010-10-22
    • 2011-08-10
    • 2018-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多