Chapters
-
Course Code
Subscribe to download the code!
Subscribe to download the code!
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
Turbo: Drive, Frames & Streams!
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Hey friends! Welcome back for part two of our Symfony UX series. The whole point of this series is to take a traditional web app - so an app with Twig templates that return HTML - and learn to do two things with it.
First, how to write truly professional JavaScript that... always works... even if some HTML is loaded via Ajax. We covered this in the first tutorial about Stimulus.
The second goal of this series is all about how we can make our app feel like a single page application. What I mean is: how we can make our site lightning fast by never having any full page refreshes. That is what Turbo gives us.
The 3 Parts of Turbo
To be more precise, Turbo is actually three different parts.
The first is "Turbo Drive". It's what turns clicks and form submits into Ajax calls. This is what gives you that single page app experience.
The second part is "Turbo Frames", which allows you to separate your page into small sections that can load and navigate independently.
And the third part is "Turbo Streams", which allows you to update any HTML element that's currently showing on the page... from inside your Symfony app. Crazy, right? When you use Turbo Streams along with Mercure, this can even give you the ability to make a real time chat app... while writing zero JavaScript.
And you're free to use all three parts... or just one or two: they operate independently.
Is Turbo New?
Now Turbo itself is... sort of brand new. If you check out its GitHub page, it's version 7.0.0-beta.5 at the time of recording. So... why is it version 7 if it's so new? Because one part of turbo - Turbo Drive, the part that turns link clicks and form submits into Ajax calls - has been around for years. It was previously called "Turbolinks" and you can still find helpful blog posts and StackOverflow answers if you search using that term.
But the other two parts - Turbo Frames and Turbo Streams are brand new. These are mostly already very good, but we will see a few rough edges and missing features along the way. But we won't let that stop us: Turbo's event system will give us the power to do almost anything.
Before we dive in, I also need to mention that Stimulus and Turbo were both affected by a serious situation at the company Basecamp. This has left both libraries without their lead developers. Am I worried? It's not ideal... but I'm not too worried. The community is large and some big companies use this technology. And at the very least, I'm confident that Turbo - or something very similar to Turbo - will be around for a long time to come. You can't stop a great idea. We're actively integrating Turbo into SymfonyCasts right now.
Project Setup
So let's do this! To "turbocharge" your learning experience you should code along with me! Hey - the puns probably won't get any better, so, settle in. Download the course code from this page. When you unzip it, you'll have a start/
directory with the same code that you see here. Check out the, README.md
file for all the setup details.
I'll go through just the last few steps. Open a terminal and move into the project. I'll use the Symfony binary to start a local web server with:
symfony serve -d
Before we go check that out, let's also make sure to run Webpack. Install the Node dependencies with:
yarn install
And... when that finishes, run Webpack with:
yarn watch
As soon as this builds... perfect - spin over to your browser and head to https://127.0.0.1:8000 to see... MVP Office Supplies! Our store for selling minimally viable office products to trendy startups. This is the same project as the first tutorial, though I did make some changes, like adding a review system below each product... and upgrading some libraries.
Now that we have this running, let's install Turbo and activate Turbo Drive to instantly eliminate full page refreshes. Woh.
20 Comments
Hey @jmsche!
It works ok for me on node 19 - just doing a composer install
, yarn install
, and yarn watch
all happen without any error on start/
and finish/
dir. It wouldn't surprise me if the build stopped working in newer Node versions (at least without updating your node deps), but I didn't hit any issues. Do you remember the problem you hit?
Cheers!
Hi Ryan,
Ran commands using node 18.10.0 here (retrieved via nvm IIRC, not sure if that matters).
Here is the error I get when I run yarn watch
in the start
folder:
yarn watch
yarn run v1.22.19
$ encore dev --watch
Browserslist: caniuse-lite is outdated. Please run:
npx browserslist@latest --update-db
Why you should do it regularly:
https://github.com/browserslist/browserslist#browsers-data-updating
Running webpack ...
node:internal/crypto/hash:71
this[kHandle] = new _Hash(algorithm, xofLen);
^
Error: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:71:19)
at Object.createHash (node:crypto:133:10)
at BulkUpdateDecorator.hashFactory (/home/jmsche/Downloads/start/node_modules/webpack/lib/util/createHash.js:145:18)
at BulkUpdateDecorator.digest (/home/jmsche/Downloads/start/node_modules/webpack/lib/util/createHash.js:80:21)
at NormalModule._initBuildHash (/home/jmsche/Downloads/start/node_modules/webpack/lib/NormalModule.js:874:53)
at /home/jmsche/Downloads/start/node_modules/webpack/lib/NormalModule.js:914:10
at processResult (/home/jmsche/Downloads/start/node_modules/webpack/lib/NormalModule.js:710:12)
at /home/jmsche/Downloads/start/node_modules/webpack/lib/NormalModule.js:809:5
at /home/jmsche/Downloads/start/node_modules/loader-runner/lib/LoaderRunner.js:399:11
at /home/jmsche/Downloads/start/node_modules/loader-runner/lib/LoaderRunner.js:251:18 {
opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ],
library: 'digital envelope routines',
reason: 'unsupported',
code: 'ERR_OSSL_EVP_UNSUPPORTED'
}
Node.js v18.10.0
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
The error seems to be the same for the finish
directory.
I had the same problem with node v20.11.1 I ran export NODE_OPTIONS=--openssl-legacy-provider
after that I can run yarn watch
Hey Yevhen,
Thanks for sharing it with others!
Cheers!
I had the same problem:
- Tried with v18.16.0 exactly the same problem
- Switched on v16.20.0 and worked and compiled
Hey Waldifubu,
Thanks for confirming it helped to you :)
Cheers!
Hey Jmsche,
Thanks for mentioning this! It might be helpful for others. I think we need to add a note about it in the course
Cheers!
Change docker-compose.yaml to :
version: '3.7'
services:
database:
image: 'arm64v8/mysql:latest'
environment:
MYSQL_ROOT_PASSWORD: password
ports:
# To allow the host machine to access the ports below, modify the lines below.
# For example, to allow the host to connect to port 3306 on the container, you would change
# "3306" to "3306:3306". Where the first port is exposed to the host and the second is the container port.
# See https://docs.docker.com/compose/compose-file/#ports for more information.
- '3306'
Change .env file and use:DATABASE_URL="mysql://root:password@127.0.0.1:3306/root?serverVersion=8.0.32"
thendocker-compose up -d
nextsymfony console doctrine:database:create
symfony console doctrine:schema:update --force
symfony console doctrine:fixtures:load
nextsymfony serve -d
nextexport NODE_OPTIONS=--openssl-legacy-provider && yarn watch
this is how the installation is working on MacBook Air M2 / nodejs LTS (18.5.0 at the time of writing) / Docker Desktop Mac
would be nice if this help someone else to save 1 hour or so....
thx
The following change:image: 'arm64v8/mysql:latest'
should not be done on an intel machine.
And thanks for the great tips!
Hey Staatzstreich,
Thank you for such a detailed tip!
Cheers!
Hey 👋
You are welcome and i like your courses!!!
Best,
Michael
Hey staatzstreich,
Thank you! We're delighted to hear such feedback, it makes our day ❤️
Stay tuned for more content soon ;)
Cheers!
Hi there, if anyone has a problem with connecting to the database, don't worry. The .env file downloaded with the project is not working.
Change the:
DATABASE_URL="postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=13&charset=utf8"
to:
DATABASE_URL="mysql://root:password@127.0.0.1:3306/root?serverVersion=5.7"
and you are good to go :)
Hey @kousaja1!
Thanks for posting this clear note! If you use the Docker database setup we describe in the README, you won't need this. But if you use your own MySQL instance without Docker (which is totally fine), then you're 100% correct 👍
Cheers!
Hi @weaverryan!
The thing is that the docker-compose provided (when you download the course code) uses mysql database, but the app is expecting posgresql database, so you need to change the .env file yourself.
Hey kousaja1!
If you're using the symfony
binary, it'll detect the database container running and expose the DATABASE_URL
for you. So if you have this setup, the DATABASE_URL
value isn't used. But if you don't use the symfony
binary, then you'll definitely need to tweak that. We mention that in the README, but it might not be clear enough.
Cheers!
Oh, that's lovely! I didn't know that the symfony binary is that smart! Thank you for the additional explanation. My bad.
Haha, no worries - it's a bit magic! And you were still right about needing to change .env if you don't use the full Docker AND symfony binary setup :).
"Houston: no signs of life"
Start the conversation!
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"composer/package-versions-deprecated": "1.11.99.1", // 1.11.99.1
"doctrine/annotations": "^1.0", // 1.13.1
"doctrine/doctrine-bundle": "^2.2", // 2.3.2
"doctrine/orm": "^2.8", // 2.9.1
"phpdocumentor/reflection-docblock": "^5.2", // 5.2.2
"sensio/framework-extra-bundle": "^6.1", // v6.1.4
"symfony/asset": "5.3.*", // v5.3.0-RC1
"symfony/console": "5.3.*", // v5.3.0-RC1
"symfony/dotenv": "5.3.*", // v5.3.0-RC1
"symfony/flex": "^1.3.1", // v1.21.6
"symfony/form": "5.3.*", // v5.3.0-RC1
"symfony/framework-bundle": "5.3.*", // v5.3.0-RC1
"symfony/property-access": "5.3.*", // v5.3.0-RC1
"symfony/property-info": "5.3.*", // v5.3.0-RC1
"symfony/proxy-manager-bridge": "5.3.*", // v5.3.0-RC1
"symfony/runtime": "5.3.*", // v5.3.0-RC1
"symfony/security-bundle": "5.3.*", // v5.3.0-RC1
"symfony/serializer": "5.3.*", // v5.3.0-RC1
"symfony/twig-bundle": "5.3.*", // v5.3.0-RC1
"symfony/ux-chartjs": "^1.1", // v1.3.0
"symfony/ux-turbo": "^1.3", // v1.3.0
"symfony/ux-turbo-mercure": "^1.3", // v1.3.0
"symfony/validator": "5.3.*", // v5.3.0-RC1
"symfony/webpack-encore-bundle": "^1.9", // v1.11.2
"symfony/yaml": "5.3.*", // v5.3.0-RC1
"twig/extra-bundle": "^2.12|^3.0", // v3.3.1
"twig/intl-extra": "^3.2", // v3.3.0
"twig/string-extra": "^3.3", // v3.3.1
"twig/twig": "^2.12|^3.0" // v3.3.2
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.0
"symfony/debug-bundle": "^5.2", // v5.3.0-RC1
"symfony/maker-bundle": "^1.27", // v1.31.1
"symfony/monolog-bundle": "^3.0", // v3.7.0
"symfony/stopwatch": "^5.2", // v5.3.0-RC1
"symfony/var-dumper": "^5.2", // v5.3.0-RC1
"symfony/web-profiler-bundle": "^5.2", // v5.3.0-RC1
"zenstruck/foundry": "^1.10" // v1.10.0
}
}
What JavaScript libraries does this tutorial use?
// package.json
{
"devDependencies": {
"@babel/preset-react": "^7.0.0", // 7.13.13
"@fortawesome/fontawesome-free": "^5.15.3", // 5.15.3
"@hotwired/turbo": "^7.0.0-beta.5", // 1.2.6
"@popperjs/core": "^2.9.1", // 2.9.2
"@symfony/stimulus-bridge": "^2.0.0", // 2.1.0
"@symfony/ux-chartjs": "file:vendor/symfony/ux-chartjs/Resources/assets", // 1.1.0
"@symfony/ux-turbo": "file:vendor/symfony/ux-turbo/Resources/assets", // 0.1.0
"@symfony/ux-turbo-mercure": "file:vendor/symfony/ux-turbo-mercure/Resources/assets", // 0.1.0
"@symfony/webpack-encore": "^1.0.0", // 1.3.0
"bootstrap": "^5.0.0-beta2", // 5.0.1
"chart.js": "^2.9.4",
"core-js": "^3.0.0", // 3.13.0
"jquery": "^3.6.0", // 3.6.0
"react": "^17.0.1", // 17.0.2
"react-dom": "^17.0.1", // 17.0.2
"regenerator-runtime": "^0.13.2", // 0.13.7
"stimulus": "^2.0.0", // 2.0.0
"stimulus-autocomplete": "https://github.com/weaverryan/stimulus-autocomplete#toggle-event-always-dist", // 2.0.0
"stimulus-use": "^0.24.0-1", // 0.24.0-2
"sweetalert2": "^11.0.8", // 11.0.12
"webpack-bundle-analyzer": "^4.4.0", // 4.4.2
"webpack-notifier": "^1.6.0" // 1.13.0
}
}
Note that you can't build assets using node 18, but node 16 seems to work without issues.