Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Deploying the Assets

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

How do we get our assets onto the site? If you "View Page Source", it looks like things are working. We see the importmap and... down here, these paths look correct: they even have the version part in their filenames.

Compiling Assets for Production

Unfortunately, all of these files return a 404. Boo. In the dev environment, when we're working locally, these files don't physically exist. But an internal Symfony listener intercepts the request, finds the file, and serves them.

But in the prod environment, that system isn't even active. It's too slow to run on production... so everything just 404s. And that's okay! A long time ago, we learned about the command to fix this:

php bin/console asset-map:compile

This command's job is simple: it takes all the assets that AssetMapper knows about and move them into the public/assets/ directory. It's not a command you need to run locally, but it is something you need to run when you deploy.

Copy this, head over to .platform.app.yaml, and go down to the build step. This is pretty cool! We're going to let Symfony do its build thing, and afterward, add our own stuff. Right here, add php bin/console asset-map:compile. That should do it!

... lines 1 - 43
hooks:
build: |
... lines 46 - 49
NODE_VERSION=18 symfony-build
php bin/console asset-map:compile
... lines 53 - 58

Why are we running this during build and not deploy? As a rule of thumb, if a command's job is to "prepare" files, it should be in the build step. Or, another way to think about it is: if a command does not require a connection to the database or any other running services, there's a good chance it's a "build" thing.

Tip

Keep your "deploy" step as fast as possible because the incoming requests are held until it finishes. You can find more information here: https://docs.platform.sh/overview/build-deploy.html#deploy-steps

Head back over here and run:

git add -p

That whitespace bothers me... so I'll fix it and preserve my sanity. Then run git commit -m with a fancy message.

git commit -m "asset-map:compile"

You know what's next. Punch it!

symfony deploy

Let's fast-forward to the good part. Here it is! We see it running the command!

Compiling assets to /app/public/assets/ Compiled 16 assets

It also writes a few other files inside the public/assets/ directory: manifest.json and importmap.json. They help Symfony dump the importmap and other things onto the page even faster.

And... done! Spin over, refresh, and... it still looks bad!? Ah, but things are not as bad as you think! Head to the homepage and open your Console. Hey! Our JavaScript is running! We see the console.log()!

Building Tailwind on Deploy

So JavaScript, check! CSS... not so much. We still have a 404 on app.tailwind.css.

Remember: when you see a 404 to a filename that does not include a version part, like here, it means that AssetMapper can't find that file. Can you spot the problem? This app.tailwind.css is a file that we're building... and it's not committed to the repository! I'll stop this command and re-run it so we can see the details. Yup, we're building the app.tailwind.css file, ignoring it from Git, and since Platform.sh deploys using our files from Git, that file is simply missing.

No big deal. This is just another thing we need to add to our build step... before we run asset-map:compile so that the file is available.

I'll paste in the code for this. This is basically the same code we ran earlier to set things up locally, except that we're using the linux-x64 build. We're downloading that, moving it into the /bin directory (it doesn't really matter where it goes), making it executable, and then running that same command so that the output file is there by the time asset-map:compile runs.

... lines 1 - 43
hooks:
build: |
... lines 46 - 51
curl -sLO https://github.com/tailwindlabs/tailwindcss/releases/download/v3.3.2/tailwindcss-linux-x64
mv tailwindcss-linux-x64 bin/tailwindcss
chmod +x bin/tailwindcss
./bin/tailwindcss -i assets/styles/app.css -o assets/styles/app.tailwind.css
... lines 56 - 63

Oh, and don't forget about the TailwindBundle which makes using Tailwind - including this deploy step - a bit easier.

Back over here, let's commit that new config change.... then deploy again:

symfony deploy

Even while it's deploying, we can see that this working. Last time, there were 16 files, now there are 17. When it finishes, spin over, refresh and... it's alive! All the pages have CSS. I love it!

Now that we're on production, let's talk about the things we need to check to make sure our assets are served blazingly fast.

Leave a comment!

0
Login or Register to join the conversation
Cat in space

"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": "*",
        "babdev/pagerfanta-bundle": "^4.0", // v4.2.0
        "doctrine/doctrine-bundle": "^2.7", // 2.10.0
        "doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.4
        "doctrine/orm": "^2.12", // 2.15.2
        "knplabs/knp-time-bundle": "^1.18", // v1.20.0
        "pagerfanta/doctrine-orm-adapter": "^4.0", // v4.1.0
        "pagerfanta/twig": "^4.0", // v4.1.0
        "stof/doctrine-extensions-bundle": "^1.7", // v1.7.1
        "symfony/asset": "6.3.*", // v6.3.0
        "symfony/asset-mapper": "6.3.*", // v6.3.0
        "symfony/console": "6.3.*", // v6.3.0
        "symfony/dotenv": "6.3.*", // v6.3.0
        "symfony/flex": "^2", // v2.3.1
        "symfony/framework-bundle": "6.3.*", // v6.3.0
        "symfony/http-client": "6.3.*", // v6.3.0
        "symfony/monolog-bundle": "^3.0", // v3.8.0
        "symfony/proxy-manager-bridge": "6.3.*", // v6.3.0
        "symfony/runtime": "6.3.*", // v6.3.0
        "symfony/stimulus-bundle": "^2.9", // v2.9.1
        "symfony/twig-bundle": "6.3.*", // v6.3.0
        "symfony/ux-turbo": "^2.9", // v2.9.1
        "symfony/web-link": "6.3.*", // v6.3.0
        "symfony/yaml": "6.3.*", // v6.3.0
        "twig/extra-bundle": "^2.12|^3.0", // v3.6.1
        "twig/twig": "^2.12|^3.0" // v3.6.1
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.4
        "symfony/debug-bundle": "6.3.*", // v6.3.0
        "symfony/maker-bundle": "^1.41", // v1.49.0
        "symfony/stopwatch": "6.3.*", // v6.3.0
        "symfony/web-profiler-bundle": "6.3.*", // v6.3.0
        "zenstruck/foundry": "^1.21" // v1.33.0
    }
}
userVoice