├── .gitignore
├── .idea
└── typescript-compiler.xml
├── LICENSE
├── README.md
├── app
├── .htaccess
├── AppCache.php
├── AppKernel.php
├── Resources
│ └── views
│ │ ├── base.html.twig
│ │ └── default
│ │ └── index.html.twig
├── autoload.php
├── config
│ ├── config.yml
│ ├── config_dev.yml
│ ├── config_prod.yml
│ ├── config_test.yml
│ ├── parameters.yml.dist
│ ├── routing.yml
│ ├── routing_dev.yml
│ ├── security.yml
│ └── services.yml
└── data.db3
├── bin
├── console
└── symfony_requirements
├── composer.json
├── composer.lock
├── phpunit.xml.dist
├── src
├── .htaccess
└── AppBundle
│ ├── AppBundle.php
│ ├── Controller
│ └── DefaultController.php
│ ├── Entity
│ └── Apartment.php
│ ├── Repository
│ └── ApartmentRepository.php
│ ├── Resources
│ └── public
│ │ ├── css
│ │ ├── app.css
│ │ └── milligram.min.css
│ │ └── js
│ │ ├── axios.min.js
│ │ ├── react
│ │ ├── app.js
│ │ └── dist
│ │ │ ├── app.2432197f.js
│ │ │ ├── app.2432197f.js.map
│ │ │ ├── index.html
│ │ │ ├── manifest.d41d8cd9.js
│ │ │ └── manifest.d41d8cd9.js.map
│ │ ├── typescript
│ │ ├── app.ts
│ │ ├── appstate.d.ts
│ │ ├── axios.d.ts
│ │ ├── dist
│ │ │ └── app.js
│ │ └── tsconfig.json
│ │ └── vue
│ │ ├── app.js
│ │ ├── tsconfig.json
│ │ └── vue.js
│ └── State
│ └── AppState.php
├── tests
└── AppBundle
│ └── Controller
│ └── DefaultControllerTest.php
├── var
├── SymfonyRequirements.php
├── cache
│ └── .gitkeep
├── logs
│ └── .gitkeep
└── sessions
│ └── .gitkeep
└── web
├── .htaccess
├── app.php
├── app_dev.php
├── apple-touch-icon.png
├── config.php
├── favicon.ico
└── robots.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | /app/config/parameters.yml
3 | /build/
4 | /phpunit.xml
5 | /var/*
6 | !/var/cache
7 | /var/cache/*
8 | !var/cache/.gitkeep
9 | !/var/logs
10 | /var/logs/*
11 | !var/logs/.gitkeep
12 | !/var/sessions
13 | /var/sessions/*
14 | !var/sessions/.gitkeep
15 | !var/SymfonyRequirements.php
16 | /vendor/
17 | /web/bundles/
18 |
--------------------------------------------------------------------------------
/.idea/typescript-compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | The MIT License
3 |
4 | Copyright (c) 2017 Jani Tarvainen, http://janit.iki.fi/
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | A Symfony hybrid app sharing state object with Twig, React and Vue
2 | ==========
3 |
4 | A Symfony project created on January 14, 2017, 9:23 am.
5 |
6 | An effort to provide a working example concept of simply
7 | sharing a state object between the Twig template rendering engine
8 | as well as JavaScript view layers Vue and React.
9 |
10 | This introduces no complexity of server side rendering for decent
11 | performance, but SSR can be done as an enhancement for improved
12 | performance and SEO: Introduction to React.js Components and Server Side Rendering in PHP, Testing React.js isomorphic rendering with php-v8js and the Symfony Microkernel
13 |
14 | This will just handle the sharing of initial state on page load
15 | and you'll need to then take over your state management in your
16 | front end using some kind of tools for that, e.g. MobX, Redux.
17 | There is also a simple API backend that also returns the same
18 | object and keeps things predictable for developers.
19 |
20 | The application comes complete with an SQLite database and built
21 | JavaScript clients to keep overhead of installation minimal. The
22 | application itself is simple enough to figure out with basic
23 | understanding of OO PHP and Symfony, so it's better just to take
24 | a look for yourself to see if this feels like a good idea or not.
25 |
26 | ## Installation
27 |
28 | Clone app:
29 |
30 | ```
31 | git clone git@github.com:janit/symfony-hybrid-twig-react-vue.git
32 | ```
33 |
34 | Install dependencies:
35 |
36 | ```
37 | composer install
38 | ```
39 |
40 | Run:
41 |
42 | ```
43 | ./bin/console server:run
44 | ```
45 |
46 | Open app in browser: http://localhost:8000
47 |
48 | ## JavaScript builds
49 |
50 | There are three separate client implementations included, React, Vue.js and Vanilla JavaScript (via TypeScript). If you want to try modifications to the behaviour of the clients you'll need to do some build setup:
51 |
52 | ### Vue.js
53 |
54 | No Vue there is build process, just start editing `src/AppBundle/Resources/public/js/vue/app.js`. Note that example uses some the ES6+ syntax is not supported natively everywhere, so you'll need an up-to-date browser.
55 |
56 | ### React
57 |
58 | The React app is built using nwb, a fast way to get started with contemporary (as of February 2017) JavaScript builds.
59 |
60 | Install nwb globally:
61 |
62 | ```
63 | npm install -g nwb
64 | ```
65 |
66 | Enter directory and run build:
67 |
68 | ```
69 | cd src/AppBundle/Resources/public/js/react
70 | react build app.js
71 | ```
72 |
73 | The built filename changes by default, so unless you tweak config, you'll need to edit `app/Resources/views/base.html.twig` to the current one.
74 |
75 | ### JavaScript / TypeScript
76 |
77 | The vanilla JavaScript app is written in TypeScript, which adds type information and some other syntax on top of the JavaScript language.
78 |
79 | The easiest way to work with TypeScript is use an editor which supports the language (such as PhpStorm, Visual Studio Code, etc...) out of the box, but otherwise you can also install the TypeScript compiler and do compilation manually:
80 |
81 | ```
82 | npm i -g typescript
83 | src/AppBundle/Resources/public/js/typescript/
84 | tsc app.ts
85 | ```
86 |
87 | The vanilla JavaScript app is written in TypeScript, which adds type information and some other syntax on top of the JavaScript language.
88 | The vanilla JavaScript app is written in TypeScript, which adds type information and some other syntax on top of the JavaScript language.
89 | ## Background information to follow
90 |
91 | As a bonus I will be adding example TypeScript Type Definitions
92 | for the example animation of how it is like to work with TypeScript
93 | and how you could benefit from using strong types in your front
94 | end development workflow.
95 |
96 | An article with the background is published here: Sharing state in a Symfony hybrid with Twig, React and other JavaScript apps
97 |
--------------------------------------------------------------------------------
/app/.htaccess:
--------------------------------------------------------------------------------
1 |
2 | Require all denied
3 |
4 |
5 | Order deny,allow
6 | Deny from all
7 |
8 |
--------------------------------------------------------------------------------
/app/AppCache.php:
--------------------------------------------------------------------------------
1 | getEnvironment(), ['dev', 'test'], true)) {
23 | $bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle();
24 | $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
25 | $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle();
26 | $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle();
27 | $bundles[] = new Symfony\Bundle\WebServerBundle\WebServerBundle();
28 | }
29 |
30 | return $bundles;
31 | }
32 |
33 | public function getRootDir()
34 | {
35 | return __DIR__;
36 | }
37 |
38 | public function getCacheDir()
39 | {
40 | return dirname(__DIR__).'/var/cache/'.$this->getEnvironment();
41 | }
42 |
43 | public function getLogDir()
44 | {
45 | return dirname(__DIR__).'/var/logs';
46 | }
47 |
48 | public function registerContainerConfiguration(LoaderInterface $loader)
49 | {
50 | $loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml');
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/Resources/views/base.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |