If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeOur source files all live in web/assets
. We code there, and Webpack moves everything we need to web/build
. At runtime, when the user actually loads the site, nothing is read from web/assets
. Nope! The user downloads all files from web/build
.
And that means... well... web/assets
does not need to be publicly accessible anymore! We can - and should - hide our source files.
Yes, I mean we can, literally:
mv web/assets assets
The assets/
directory now lives at the root of our project.
And really... that doesn't break much. All of our files use relative paths internally to refer to each other. The only thing we need to update is webpack.config.js
: to remove the web/
from the 3 entries:
... lines 1 - 3 | |
module.exports = { | |
entry: { | |
rep_log: './assets/js/rep_log.js', | |
login: './assets/js/login.js', | |
layout: './assets/js/layout.js', | |
}, | |
... lines 10 - 63 | |
}; |
Yep, that's it.
Find your webpack
terminal tab and restart!
./node_modules/.bin/webpack --watch
Everything still builds... and the page still loads fine.
Except... we lost something small. Before this change, the leaderboard had a little dumbbell image. Inspect that element. Yea, inside the h2
, there is a good, old-fashioned img
tag. And it references /assets/images/dumbbell.png
. I was wrong! I said nothing was referencing the public web/assets
directory. But that's not true!
In app/Resources/views/lift/index.html.twig
, yep, there is the img
tag:
... lines 1 - 2 | |
{% block body %} | |
<div class="row"> | |
... lines 5 - 34 | |
<div class="col-md-5"> | |
<div class="leaderboard"> | |
<h2 class="text-center"> | |
<img class="dumbbell" src="{{ asset('assets/images/dumbbell.png') }}" /> | |
Leaderboard | |
</h2> | |
... lines 41 - 42 | |
</div> | |
</div> | |
</div> | |
{% endblock %} | |
... lines 47 - 53 |
How can we fix this? It would be silly to keep all of our source files in a public directory just so we can reference a few, static images.
The answer? With a plugin called copy-webpack-plugin
. Google for it.
This plugin is a little tool that allows you to copy files from one location to another when Webpack runs. For us, it means we could copy files to the build/
directory that aren't processed through Webpack.
Let's get it installed! Copy the name of the package. Then, in your favorite open terminal tab, run:
yarn add copy-webpack-plugin@4 --dev
Back in the documentation, copy the require
line. In our webpack.config.js
, paste that, but use the trendier const
keyword:
... lines 1 - 2 | |
const CopyWebpackPlugin = require('copy-webpack-plugin'); | |
... lines 4 - 71 |
I'll also copy the new CopyWebpackPlugin()
line. This goes under the plugins
key:
... lines 1 - 2 | |
const CopyWebpackPlugin = require('copy-webpack-plugin'); | |
module.exports = { | |
... lines 6 - 58 | |
plugins: [ | |
... lines 60 - 64 | |
new CopyWebpackPlugin([ | |
... lines 66 - 67 | |
]), | |
] | |
}; |
So here's the deal: in the images/
directory, we have a mixture of images. One - dumbbell-mini.png
- is processed through Webpack and copied to the build/
directory already. But the other, dumbbell.png
is not.
To organize this, create a new directory in assets/
called static/
. Move the dumbbell file there. This directory will hold all assets that are not processed by Webpack.
Now, for CopyWebpackPlugin
, we will copy from ./assets/static
to static/
. I'll add a comment about what this means: copies to {output}/static
:
... lines 1 - 2 | |
const CopyWebpackPlugin = require('copy-webpack-plugin'); | |
module.exports = { | |
... lines 6 - 58 | |
plugins: [ | |
... lines 60 - 64 | |
new CopyWebpackPlugin([ | |
// copies to {output}/static | |
{ from: './assets/static', to: 'static' } | |
]), | |
] | |
}; |
Give it a try! Hit Ctrl
+C
to stop Webpack, then restart it!
yarn add copy-webpack-plugin --dev
And instantly, we have a web/build/static
directory with dumbbell.png
inside!
This is nothing crazy, but it works well! In our template - index.html.twig
- change the src
to build/static/dumbbell.png
:
... lines 1 - 2 | |
{% block body %} | |
<div class="row"> | |
... lines 5 - 34 | |
<div class="col-md-5"> | |
<div class="leaderboard"> | |
<h2 class="text-center"> | |
<img class="dumbbell" src="{{ asset('build/static/dumbbell.png') }}" /> | |
Leaderboard | |
</h2> | |
... lines 41 - 42 | |
</div> | |
</div> | |
</div> | |
{% endblock %} | |
... lines 47 - 53 |
Also open login.html.twig
: we have another img
tag there too:
... lines 1 - 10 | |
{% block fos_user_content %} | |
<div class="container"> | |
<div class="wrapper"> | |
<form action="{{ path("fos_user_security_check") }}" method="post" class="form-signin"> | |
<h3><img class="dumbbell" src="{{ asset('build/static/dumbbell.png') }}">Login! Start Lifting!</h3> | |
... lines 16 - 61 | |
</form> | |
</div> | |
</div> | |
{% endblock fos_user_content %} |
When we refresh, no nasty surprises this time! The image loads.
Next! Let's add some fanciness to our CSS... by using Sass...
// composer.json
{
"require": {
"php": "^7.2.0",
"symfony/symfony": "3.3.*", // v3.3.16
"twig/twig": "2.10.*", // v2.10.0
"doctrine/orm": "^2.5", // v2.7.0
"doctrine/doctrine-bundle": "^1.6", // 1.10.3
"doctrine/doctrine-cache-bundle": "^1.2", // 1.3.5
"symfony/swiftmailer-bundle": "^2.3", // v2.6.3
"symfony/monolog-bundle": "^2.8", // v2.12.1
"symfony/polyfill-apcu": "^1.0", // v1.4.0
"sensio/distribution-bundle": "^5.0", // v5.0.22
"sensio/framework-extra-bundle": "^3.0.2", // v3.0.26
"incenteev/composer-parameter-handler": "^2.0", // v2.1.2
"friendsofsymfony/user-bundle": "^2.0", // v2.1.2
"doctrine/doctrine-fixtures-bundle": "~2.3", // v2.4.1
"doctrine/doctrine-migrations-bundle": "^1.2", // v1.3.2
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"friendsofsymfony/jsrouting-bundle": "^1.6" // 1.6.0
},
"require-dev": {
"sensio/generator-bundle": "^3.0", // v3.1.6
"symfony/phpunit-bridge": "^3.0" // v3.3.5
}
}
// package.json
{
"dependencies": [],
"devDependencies": {
"babel-core": "^6.25.0", // 6.25.0
"babel-loader": "^7.1.1", // 7.1.1
"babel-plugin-syntax-dynamic-import": "^6.18.0", // 6.18.0
"babel-preset-env": "^1.6.0", // 1.6.0
"bootstrap-sass": "^3.3.7", // 3.3.7
"clean-webpack-plugin": "^0.1.16", // 0.1.16
"copy-webpack-plugin": "^4.0.1", // 4.0.1
"core-js": "^2.4.1", // 2.4.1
"css-loader": "^0.28.4", // 0.28.4
"extract-text-webpack-plugin": "^3.0.0", // 3.0.0
"file-loader": "^0.11.2", // 0.11.2
"font-awesome": "^4.7.0", // 4.7.0
"jquery": "^3.2.1", // 3.2.1
"lodash": "^4.17.4", // 4.17.4
"node-sass": "^4.5.3", // 4.5.3
"resolve-url-loader": "^2.1.0", // 2.1.0
"sass-loader": "^6.0.6", // 6.0.6
"style-loader": "^0.18.2", // 0.18.2
"sweetalert2": "^6.6.6", // 6.6.6
"webpack": "^3.4.1", // 3.4.1
"webpack-chunk-hash": "^0.4.0", // 0.4.0
"webpack-dev-server": "^2.6.1", // 2.6.1
"webpack-manifest-plugin": "^1.2.1" // 1.2.1
}
}
When adding copy-webpack-plugin this tutorial needs version 4 since version 5 is now out. Should be
yarn add copy-webpack-plugin@4 --dev