{"id":23771092,"url":"https://github.com/reed-jones/phase","last_synced_at":"2025-09-05T14:33:54.274Z","repository":{"id":39260582,"uuid":"234967925","full_name":"reed-jones/phase","owner":"reed-jones","description":"A Laravel driven Vuex \u0026 Vue-Router orchestration library","archived":false,"fork":false,"pushed_at":"2023-11-04T18:56:07.000Z","size":4572,"stargazers_count":10,"open_issues_count":23,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-08T20:57:05.909Z","etag":null,"topics":["laravel","phase","single-page-app","vue","vue-router","vuex"],"latest_commit_sha":null,"homepage":"https://phased.dev","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/reed-jones.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"reed-jones","ko_fi":"rj0nz","custom":"buymeacoffee.com/reedjones"}},"created_at":"2020-01-19T21:08:38.000Z","updated_at":"2025-07-21T23:42:35.000Z","dependencies_parsed_at":"2024-06-19T19:05:52.741Z","dependency_job_id":"3bfc7191-4824-4837-a5e9-4414eb6ad2cb","html_url":"https://github.com/reed-jones/phase","commit_stats":{"total_commits":123,"total_committers":3,"mean_commits":41.0,"dds":"0.16260162601626016","last_synced_commit":"7ebcb10dde09182bdc14b9b63677d2a99bb30282"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/reed-jones/phase","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reed-jones%2Fphase","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reed-jones%2Fphase/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reed-jones%2Fphase/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reed-jones%2Fphase/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reed-jones","download_url":"https://codeload.github.com/reed-jones/phase/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reed-jones%2Fphase/sbom","scorecard":{"id":768322,"data":{"date":"2025-08-11","repo":{"name":"github.com/reed-jones/phase","commit":"4115f3c06d89ad3fcc089439c6bbc90a38f8ae0a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.6,"checks":[{"name":"Code-Review","score":0,"reason":"Found 1/28 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":9,"reason":"binaries present in source code","details":["Warn: binary detected: build/splitsh-lite:1"],"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENCE.md:0","Info: FSF or OSI recognized license: ISC License: LICENCE.md:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 4 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"140 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-4qwp-7c67-jmcc","Warn: Project is vulnerable to: GHSA-25mq-v84q-4j7r","Warn: Project is vulnerable to: GHSA-cwmx-hcrq-mhc3","Warn: Project is vulnerable to: GHSA-f2wf-25xc-69c9","Warn: Project is vulnerable to: GHSA-q559-8m2m-g699","Warn: Project is vulnerable to: GHSA-w248-ffj2-4v5q","Warn: Project is vulnerable to: GHSA-q7rv-6hp3-vh96","Warn: Project is vulnerable to: GHSA-wxmh-65f7-jcvw","Warn: Project is vulnerable to: GHSA-3p32-j457-pg5x","Warn: Project is vulnerable to: GHSA-44pg-c29v-hp6r","Warn: Project is vulnerable to: GHSA-66hf-2p6w-jqfw","Warn: Project is vulnerable to: GHSA-78fx-h6xr-vch4","Warn: Project is vulnerable to: GHSA-gv7v-rgg6-548h","Warn: Project is vulnerable to: GHSA-jwvj-pwww-3mj5","Warn: Project is vulnerable to: GHSA-w68r-5p45-5rqp","Warn: Project is vulnerable to: GHSA-wq8p-mqvg-2p5h","Warn: Project is vulnerable to: GHSA-x7p5-p2c9-phvg","Warn: Project is vulnerable to: GHSA-3527-qv2q-pfvx","Warn: Project is vulnerable to: GHSA-c2pc-g5qf-rfrf","Warn: Project is vulnerable to: GHSA-9f46-5r25-5wfm","Warn: Project is vulnerable to: GHSA-j3f9-p6hm-5w6q","Warn: Project is vulnerable to: GHSA-wjv8-pxr6-5f4r","Warn: Project is vulnerable to: GHSA-mrqx-rp3w-jpjp","Warn: Project is vulnerable to: GHSA-754h-5r27-7x3r","Warn: Project is vulnerable to: GHSA-h7vf-5wrv-9fhv","Warn: Project is vulnerable to: GHSA-qq5c-677p-737q","Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-whgm-jr23-g3j9","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-fwr7-v2mv-hh25","Warn: Project is vulnerable to: GHSA-4w2v-q235-vp99","Warn: Project is vulnerable to: GHSA-cph5-m8f7-6c5x","Warn: Project is vulnerable to: GHSA-wf5p-g6vw-rhxx","Warn: Project is vulnerable to: GHSA-jr5f-v2jv-69x6","Warn: Project is vulnerable to: GHSA-qwcr-r2fm-qrc7","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-x9w5-v3q2-3rhw","Warn: Project is vulnerable to: GHSA-w8qv-6jwh-64r5","Warn: Project is vulnerable to: GHSA-257v-vj4p-3w2h","Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-3wcq-x3mq-6r9p","Warn: Project is vulnerable to: GHSA-r9p9-mrjm-926w","Warn: Project is vulnerable to: GHSA-434g-2637-qmqr","Warn: Project is vulnerable to: GHSA-49q7-c7j4-3p7m","Warn: Project is vulnerable to: GHSA-977x-g7h5-7qgw","Warn: Project is vulnerable to: GHSA-f7q4-pwc6-w24p","Warn: Project is vulnerable to: GHSA-fc9h-whq2-v747","Warn: Project is vulnerable to: GHSA-vjh7-7g9h-fjfh","Warn: Project is vulnerable to: GHSA-6h5x-7c5m-7cr7","Warn: Project is vulnerable to: GHSA-rv95-896h-c2vc","Warn: Project is vulnerable to: GHSA-qw6h-vgh9-j6wx","Warn: Project is vulnerable to: GHSA-74fj-2j2h-c42q","Warn: Project is vulnerable to: GHSA-pw2r-vq6v-hr8c","Warn: Project is vulnerable to: GHSA-jchw-25xp-jwwc","Warn: Project is vulnerable to: GHSA-cxjh-pqwp-8mfp","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-ww39-953v-wcq6","Warn: Project is vulnerable to: GHSA-pfq8-rq6v-vf5m","Warn: Project is vulnerable to: GHSA-c7qv-q95q-8v27","Warn: Project is vulnerable to: GHSA-qqgx-2p2h-9c37","Warn: Project is vulnerable to: GHSA-78xj-cgh5-2h22","Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp","Warn: Project is vulnerable to: GHSA-7r28-3m3f-r2pr","Warn: Project is vulnerable to: GHSA-r8j5-h5cx-65gg","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-76p3-8jx3-jpfq","Warn: Project is vulnerable to: GHSA-3rfm-jhwj-7488","Warn: Project is vulnerable to: GHSA-hhq3-ff78-jv3g","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-8hfj-j24r-96c4","Warn: Project is vulnerable to: GHSA-wc69-rhjr-hc9g","Warn: Project is vulnerable to: GHSA-92xj-mqp7-vmcj","Warn: Project is vulnerable to: GHSA-wxgw-qj99-44c2","Warn: Project is vulnerable to: GHSA-5rrq-pxf6-6jx5","Warn: Project is vulnerable to: GHSA-8fr3-hfg3-gpgp","Warn: Project is vulnerable to: GHSA-gf8q-jrpm-jvxq","Warn: Project is vulnerable to: GHSA-2r2c-g63r-vccr","Warn: Project is vulnerable to: GHSA-cfm4-qjh2-4765","Warn: Project is vulnerable to: GHSA-x4jg-mjrx-434g","Warn: Project is vulnerable to: GHSA-5fw9-fq32-wv5p","Warn: Project is vulnerable to: GHSA-rp65-9cf3-cjxr","Warn: Project is vulnerable to: GHSA-cwx2-736x-mf6w","Warn: Project is vulnerable to: GHSA-v39p-96qg-c8rf","Warn: Project is vulnerable to: GHSA-8v63-cqqc-6r2c","Warn: Project is vulnerable to: GHSA-76c9-3jph-rj3q","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j","Warn: Project is vulnerable to: GHSA-rhx6-c78j-4q9w","Warn: Project is vulnerable to: GHSA-h7cp-r72f-jxh6","Warn: Project is vulnerable to: GHSA-v62p-rq8g-8h59","Warn: Project is vulnerable to: GHSA-566m-qj78-rww5","Warn: Project is vulnerable to: GHSA-7fh5-64p2-3v2j","Warn: Project is vulnerable to: GHSA-hwj9-h5mp-3pm3","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-m6fv-jmcg-4jfg","Warn: Project is vulnerable to: GHSA-hxcc-f52p-wc94","Warn: Project is vulnerable to: GHSA-cm22-4g7w-348p","Warn: Project is vulnerable to: GHSA-vx3p-948g-6vhq","Warn: Project is vulnerable to: GHSA-4wf5-vphf-c2xc","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-9m6j-fcg5-2442","Warn: Project is vulnerable to: GHSA-hh27-ffr2-f2jc","Warn: Project is vulnerable to: GHSA-rqff-837h-mm52","Warn: Project is vulnerable to: GHSA-8v38-pw62-9cw2","Warn: Project is vulnerable to: GHSA-hgjh-723h-mx2j","Warn: Project is vulnerable to: GHSA-jf5r-8hm2-f872","Warn: Project is vulnerable to: GHSA-5j4c-8p2g-v4jx","Warn: Project is vulnerable to: GHSA-g3ch-rx76-35fx","Warn: Project is vulnerable to: GHSA-wr3j-pwj9-hqq6","Warn: Project is vulnerable to: GHSA-4v9v-hfq4-rm2v","Warn: Project is vulnerable to: GHSA-9jgg-88mc-972h","Warn: Project is vulnerable to: GHSA-6fc8-4gx4-v693","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q","Warn: Project is vulnerable to: GHSA-c4w7-xm78-47vh","Warn: Project is vulnerable to: GHSA-p9pc-299p-vxgp","Warn: Project is vulnerable to: GHSA-ff7x-qrg7-qggm","Warn: Project is vulnerable to: GHSA-4gmj-3p3h-gm8h","Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj","Warn: Project is vulnerable to: GHSA-w7rc-rwvf-8q5r","Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g","Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm","Warn: Project is vulnerable to: GHSA-44c6-4v22-4mhx","Warn: Project is vulnerable to: GHSA-4x5v-gmq8-25ch","Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v","Warn: Project is vulnerable to: GHSA-7p7h-4mm5-852v","Warn: Project is vulnerable to: GHSA-38fc-wpqx-33j7","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-23T01:30:29.345Z","repository_id":39260582,"created_at":"2025-08-23T01:30:29.345Z","updated_at":"2025-08-23T01:30:29.345Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272821200,"owners_count":24998599,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-30T02:00:09.474Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["laravel","phase","single-page-app","vue","vue-router","vuex"],"created_at":"2025-01-01T03:28:32.437Z","updated_at":"2025-09-05T14:33:49.192Z","avatar_url":"https://github.com/reed-jones.png","language":"PHP","readme":"# [Phase](https://phased.dev)\n\n![Build Status](https://app.chipperci.com/projects/9b19fe8f-bd39-4f36-aa2f-f7d313e23b58/status/master) ![Composer Version](https://img.shields.io/packagist/v/phased/phase?label=composer) ![NPM Version](https://img.shields.io/npm/v/@phased/phase)\n\n## [Demo](https://github.com/reed-jones/phase-blog-demo)\nCheck out the demo. Deploy a fully configured Phase app in minutes, poke around, change things, view source, have fun!\n\n---\n\nThis following README can be a little rough around the edges, and is meant more as a quick reference than a guide. There is an ongoing effort to improve the documentation found at [phased.dev](https://phased.dev), which is where you should start if you are new to phase. If your having trouble setting Phase up, or if something isn't working as expected, feel free to [open an issue](https://github.com/reed-jones/phase/issues/new).\n\n---\n\nContributions welcome! contributions come in all forms, bug reports, questions asked, questions answered, documentation, and of course writing code. If your interested, but not sure where to start, open an issue.\n\n---\n\n## Why\nPhase aims to integrate Laravel, Vuex, \u0026 Vue Router as seamlessly as possible. All phase routes specified in your `routes/web.php` are automatically configured for slick SPA navigation. All configured api calls will automatically be committed into your vuex store. Data loaded through your view controllers is immediately available in the vuex store. No waiting for separate api calls, No `mutation` boilerplate: `state.count = count`. No chance of your vue-router configuration getting out of sync with your web routes. No reason to give up the nice Route -\u003e Controller -\u003e Page view flow.\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch2\u003eInstallation\u003c/h2\u003e\u003c/summary\u003e\n  - `npm install --save-dev @phased/phase`\n  - `composer require phased/routing`\n  - `composer require phased/state`\n\n  - * Note Currently routing depends on state being installed, but further decoupling is planned so that the two packages may be used independently. State however is standalone at this point and can be used by itself if no SPA routing is required. For this configuration only `npm install @phased/state` \u0026 `composer require phased/state` are needed.\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch2\u003eClient Setup (Front End)\u003c/h2\u003e\u003c/summary\u003e\n  \nBoth state \u0026 routing rely on `axios` being globally available, in order to automatically configure the interceptors required. You may do this however you wish, but the standard lines that come with Laravel work just fine.\n```js\nwindow.axios = require('axios');\nwindow.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';\n```\n\n### Vuex Integration/State Management\nFollow the official Vuex installation/setup. When you create your store, wrap your options using the @phased/state `hydrate` method. Adding onto the Vuex [Simplest Store](https://vuex.vuejs.org/guide/#the-simplest-store) example:\n```js\n// store.js\nimport Vue from 'vue'\nimport Vuex, { Store } from 'vuex'\nimport { hydrate } from '@phased/state'\n\nVue.use(Vuex)\n\nexport default new Store(hydrate({\n  state: {\n    count: 0\n  },\n  mutations: {\n    increment (state) {\n      state.count++\n    }\n  }\n}))\n```\n\n### Vue Router/Route Management\nFront end Vue Router integration falls into two steps. Configuring Laravel Mix (or Webpack), and setting up the router. Router setup is regular vue-router setup, so feel free to refer to the [docs.](https://router.vuejs.org/guide/). Phased however makes it much simpler as it supplies the route definitions. Below is a simple, yet complete example of the router configuration. For many use cases, this is all that will be required.\n```js\n// router.js\nimport Vue from 'vue'\nimport VueRouter from 'vue-router';\nimport PhaseRoutes from '@phased/phase/routes'\n\nVue.use(VueRouter)\n\nexport default new VueRouter({\n    mode: 'history',\n    routes: PhaseRoutes\n})\n```\n\nFinally if using Laravel-mix add\n```js\n// webpack.mix.js\nconst mix = require('laravel-mix')\nrequire('@phased/phase')\nmix.phase()\n```\n\nAlternatively the webpack plugin is exposed, and can be used directly\n```js\nconst VueRouterAutoloadPlugin = require(\"@phased/webpack-plugin\")\n//...\n  plugins: [\n    new VueRouterAutoloadPlugin({})\n  ]\n```\n\nPhase configuration pulls the required assets (js/scss files) from the phase config,\nA slightly more complex/realistic configuration with tailwind setup would look along the lines of\n```js\n// webpack.mix.js\nconst mix = require('laravel-mix')\nconst path = require('path')\nconst tailwindcss = require('tailwindcss')\nrequire('laravel-mix-purgecss');\nrequire('@phased/phase')\n\nmix\n    .webpackConfig({\n        resolve: { alias: { \"@\": path.resolve(__dirname, 'resources', 'js') } },\n    })\n    .options({\n        processCssUrls: false,\n        postCss: [ tailwindcss('./tailwind.config.js') ],\n    })\n    .purgeCss()\n    .phase()\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch2\u003eServer Setup (Back End)\u003c/h2\u003e\u003c/summary\u003e\n\nAfter installing both routing \u0026 state components with composer, Phase is ready to roll. No really. Thats all the required setup. For more customization options, a 'phased' config is exposed and can be published. `php artisan vendor:publish --provider=\"Phased\\Routing\\PhasedRoutingServiceProvider\" --tag=\"config\"`\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch2\u003eRouting\u003c/h2\u003e\u003c/summary\u003e\n\nSPA Routing starts with by defining your page routes as 'phase' routes. Traditionally these are placed in `routes/web.php`. In a regular app these would be 'Route::get' routes whose controller returns a view(). In a Phase app, just change it to `Route::phase`, and change your controller so that it returns `Phase::view()`. Modifying the [basic controller laravel example](https://laravel.com/docs/6.x/controllers#basic-controllers):\n```diff\n\u003c?php\n\nnamespace App\\Http\\Controllers;\n\n+ use Phased\\Routing\\Facades\\Phase;\n+ use Phased\\State\\Facades\\Vuex;\nuse App\\Http\\Controllers\\Controller;\nuse App\\User;\n\nclass UserController extends Controller\n{\n    /**\n     * Show the profile for the given user.\n     *\n     * @param  int  $id\n     * @return View\n     */\n-    public function show($id)\n+    public function UserProfile($id)\n    {\n-        return view('user.profile', ['user' =\u003e User::findOrFail($id)]);\n+        Vuex::state([ 'user' =\u003e User::findOrFail($id) ]);\n+        return Phase::view();\n    }\n}\n```\n\nAnd defining the route:\n```diff\n-Route::get('user/{id}', 'UserController@show');\n+Route::phase('user/{id}', 'UserController@UserProfile');\n```\n\nNow navigating to `/user/{id}` will display `resources/js/pages/UserController/UserProfile.vue`, and the user with id `$id`, will be loaded into your vuex store at `this.$store.state.user`. Creating a second page and navigating between the two using [\u003crouter-link\u003e](https://router.vuejs.org/api/#router-link) will automatically handle vuex store updating based on the data loaded in the controller, while using nice SPA page transitions.\n\nTo get a list of all registered phase routes, the command `php artisan phase:routes` will list a table similar to `route:list`.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch2\u003eState Management\u003c/h2\u003e\u003c/summary\u003e\nState Management from a Phase app is used through the `Vuex` facade provided, as well as the Collection, and Model Helpers. The Facade contains two primary data loading functions.\n\n### State\n\n```php\nVuex::state($state);\n```\n`state` accepts an array of values, which will be merged in/set as the base vuex state object.\n```js\n// Basic Vuex store.\nexport default new Store(hydrate({\n  state: {\n    count: 0,\n    app: ''\n  }\n}))\nconsole.log(this.$store.state.count) // 0\n```\nAll or some of the keys can be updated at the same time.\n```php\n// From a controller or model\nVuex::state([ 'count' =\u003e 1 ]);\n```\n\n```js\nconsole.log(this.$store.state.count) // 1\n```\n\n### Module\n\nThe other and perhaps more used variant is `Vuex::module($namespace, $data);`. This updates a [vuex module](https://vuex.vuejs.org/guide/modules.html) with the given data, much like how `::state` works.\n\n```js\n// Basic Vuex store.\nexport default new Store(hydrate({\n  modules: {\n    user: {\n      state: {\n        name: '',\n      }\n    },\n    app: {\n      modules: {\n        options: {\n          state: {\n            version: '0.0.0'\n          }\n        }\n      }\n    }\n  }\n}))\n\nconsole.log(this.$store.state.user.name) // ''\nconsole.log(this.$store.state.app.options.version) // '0.0.0'\n```\n\n```php\nVuex::module('user', [ 'name' =\u003e 'Reed' ]);\n\n// Nested Modules\nVuex::module('app/options', [ 'version' =\u003e '0.0.4' ]);\n```\n```js\nconsole.log(this.$store.state.user.name) // 'Reed'\nconsole.log(this.$store.state.app.options.version) // '0.0.4'\n```\n\n### Collections\n\nOut of the box, Collections have been extended so that they now have a `-\u003etoVuex` method. This takes two arguments, the vuex namespace, and the key in which to save the data. Take the following example.\n```js\nexport default new Store(hydrate({\n  modules: {\n    flights: {\n      state: {\n        selected: null,\n        in_flight: []\n      }\n    }\n  }\n}))\n```\n```php\nApp\\Flight::query()\n  -\u003ewhere('in_flight', true)\n  -\u003eget()\n  -\u003etoVuex('flights', 'in_flight');\n```\n\n### Models\n\nMuch like Collections, Models can have a -\u003etoVuex method, this however is applied via a trait, and not available out of the box.\n```php\n// Flight Model\nuse Phased\\State\\Traits\\Vuexable;\n\nclass Flight extends Model\n{\n    use Vuexable;\n}\n\n// Elsewhere...\nApp\\Flight::find(5)-\u003etoVuex('flights', 'selected');\n```\n\n### Mutations\nAlthough the above approaches cover a wide range of use cases, sometimes a bit more finesse may be required. For a bit more control, the `Vuex::commit($mutation, $value);` is provided. This allows full control for calling your vuex mutations from your controllers. These mutations will be called _after_ all the 'automatic' mutations above (`toVuex`, `::module`, `::state`), however the order in which the mutations are called cannot be relied upon.\n```php\nuse Phased\\State\\Facades\\Vuex;\n\nVuex::commit('SET_COUNT', 5);\nVuex::commit('user/SET_USER', Auth::user());\n```\n\n### Actions\nMuch like mutations above, Actions can be called using the `dispatch` method.\n```php\nuse Phased\\State\\Facades\\Vuex;\n\nVuex::dispatch('increment', 5);\nVuex::dispatch('user/setActive', Auth::user());\n```\n\n### Module Loaders\nVery often you will want your vuex modules to be loaded in the same way. Phase provides the concept of Module Loaders for this purpose. A Module Loader is associated with a vuex module on the front end, and a method can be created for each root level key in that modules state. All Module Loaders following the naming convention of `app/VuexLoaders/{namespace}ModuleLoader.php` will get automatically discovered, however you can register any class manually in the `boot` method of your application's `AppServiceProvider`.\n\n```php\nuse Phased\\State\\Facades\\Vuex;\n\n// Custom module registration\nVuex::register([\n  MyVuexModuleLoader::class,\n]);\n```\n\nThe Vuex namespace will be guessed based on the class name, and naming conventions, however if needed, the namespace can be specified by adding `protected $namespace = 'app/users';`\n\nA Module Loader is likely best explained through examples. Given the following `users` vuex module:\n```js\n// 'users' Vuex Module\nconst state = {\n  all: [],\n  active: null,\n  count: 0\n}\n```\nA matching Module Loader could be written as\n```php\n// app/VuexLoaders/UsersModuleLoader.php\nnamespace App\\VuexLoaders;\n\nuse App\\User;\nuse Illuminate\\Support\\Facades\\Auth;\nuse Phased\\State\\Support\\VuexLoader as ModuleLoader;\n\nclass AppModuleLoader extends ModuleLoader\n{\n  /**\n   * Gets a list of all available users\n   *\n   * @return \\Illuminate\\Support\\Collection\n   */\n  public function all()\n  {\n    return User::select('id', 'name')-\u003eget();\n  }\n\n  /**\n   * Gets the details for the requested user\n   *\n   * @return App\\User\n   */\n  public function active($id)\n  {\n    return User::find($id);\n  }\n\n  /**\n   * Gets the total count of all the users in the system\n   *\n   * @return int\n   */\n  public function count()\n  {\n    return User::count();\n  }\n}\n```\n\nNow anytime you need to fetch this data, it can be called using the `load` or `lazyLoad` methods.\n```php\nuse Phased\\State\\Facades\\Vuex;\n\n// Loads all users into users module at $store.state.users.all\nVuex::load('users', 'all');\n// Loads user 1 into users.active\nVuex::load('users', 'active', 1);\n// Load multiple keys at once\nVuex::load('users', [\n  'all',\n  'active' =\u003e 1,\n  'count'\n]);\n```\n\nIn some cases you may need to lazy load the data. A common use case for this is attaching key user details on page load. You might try to accomplish this by adding something like the following in `AppServiceProvider`.\n```php\n// AppServiceProvider\npublic function boot()\n{\n  if (!request()-\u003eexpectsJson()) {\n    Vuex::load('auth', 'user');\n  }\n}\n\n// AuthModuleLoader.php\npublic function user()\n{\n  return Auth::user();\n}\n```\nHowever since this runs before the auth middleware, `Auth::user()` will always return null. This is easily fixed using 'lazy loading'. Normally data is eagerly loaded when the function is called, with Lazy Loading however the data is put in queue and not loaded until the final response is being formed.\n```php\nVuex::lazyLoad('auth', 'user');\n```\n\n### Lazy Loading\nIn addition to the Module Loader `::lazyLoad` convenience method, any data can be lazy loaded by providing a function which returns the data instead of the data itself.\n\n```php\n// Lazy load the entire object\nVuex::module('user', fn() =\u003e ['active' =\u003e Auth::user() ] );\n\n// Lazy Load a single key\nVuex::module('user', [\n  'active' =\u003e function () {\n    return Auth::user();\n  }\n]);\n\n// These work with state too\nVuex::state(['number' =\u003e fn() =\u003e 5]);\nVuex::state(function () {\n  return ['number' =\u003e 5]\n});\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch2\u003eServer Side Rendering\u003c/h2\u003e\u003c/summary\u003e\n\nServer side rendering (SSR) is disabled out of the box, due to the fact that writing \"universal\" or \"isomorphic\" javascript can be a little more complex than standard Javascript, however there are great resources out there if you are curious: https://ssr.vuejs.org/guide/universal.html . To enable SSR in your Phase app, first add `NODE_PATH=` to your .env with the path to your node binary. Then simply update your `ssr` option in your config to be true. Now when you 'view source' \u0026 refresh the page you should see the raw html instead of the standard `\u003cdiv id=\"app\"\u003e\u003c/div\u003e`. The other option available is `hydrate`. With this set to true, your vue app will be 'hydrated' with all the interactive elements \u0026 components you would expect from a vue app. When set to false, no Javascript is loaded on your page which depending on your goals may or may not be what you are looking for. Although a little out of date, and example of a non-hydrated app (albeit not built with phase) is [Netflix circa 2017](https://jakearchibald.com/2017/netflix-and-react/). Phase attempts to remove the barrier and make SSR easy, however there are a few rules you still need to follow in order to successfully write a universal app. The most important and easy to forget is you can no longer rely on the browser global api to be available. That means when the app is run on the server, there is no `window` or `document`,\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch2\u003eTroubleshooting\u003c/h2\u003e\u003c/summary\u003e\n  - `Vuex::dd();` or `dd(Vuex::toArray());` will dump all the currently saved vuex state\n  - For Api calls, any mutations will (should) be visible from within the Vue DevTools mutations tab\n \u003c/details\u003e\n \n \n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch2\u003eExample\u003c/h2\u003e\u003c/summary\u003e\n## Example\nTo kick things off with a basic example, lets create a simple controller and load the first page of our new app.\n```sh\nphp artisan make:controller PhaseController\n```\n\nNow go to your `routes/web.php` and add your first route\n```php\n//routes/web.php\nRoute::phase('/', 'PhaseController@HomePage');\n```\n\nNow open up the controller and create the `HomePage` method. Notice the return statement. `Phase::view()` handle syncing the correct data flow for the page routes. It will automatically switch between loading the page, and just updating your vuex state with the appropriate data. If the method is strictly for API calls, then returning only the updated vuex state with `return response()-\u003evuex();` will suffice, however for now, its a page load so `Phase::view();` it is.\n```php\n\u003c?php\n\nnamespace App\\Http\\Controllers;\n\nuse Phased\\Routing\\Facades\\Phase;\nuse Phased\\State\\Facades\\Vuex;\n\nclass PhaseController extends Controller\n{\n    public function HomePage()\n    {\n        return Phase::view();\n    }\n}\n```\n\nNow run laravel-mix and load the page. If all went well, The required .vue files have been generated if they didn't already exist, and the page should load up.\n\u003c/details\u003e\n","funding_links":["https://github.com/sponsors/reed-jones","https://ko-fi.com/rj0nz","buymeacoffee.com/reedjones"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freed-jones%2Fphase","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freed-jones%2Fphase","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freed-jones%2Fphase/lists"}