// composer.json
{
"require": {
"php": "^7.2.0",
"ext-iconv": "*",
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"doctrine/doctrine-bundle": "^1.6", // 1.8.1
"doctrine/doctrine-cache-bundle": "^1.2", // 1.3.2
"doctrine/doctrine-fixtures-bundle": "~3.0", // 3.0.2
"doctrine/doctrine-migrations-bundle": "^1.2", // v1.3.1
"doctrine/orm": "^2.5", // v2.7.2
"friendsofsymfony/jsrouting-bundle": "^2.2", // 2.2.0
"friendsofsymfony/user-bundle": "dev-master", // dev-master
"sensio/framework-extra-bundle": "^5.1", // v5.1.5
"symfony/asset": "^4.0", // v4.0.4
"symfony/console": "^4.0", // v4.0.4
"symfony/flex": "^1.0", // v1.17.6
"symfony/form": "^4.0", // v4.0.4
"symfony/framework-bundle": "^4.0", // v4.0.4
"symfony/lts": "^4@dev", // dev-master
"symfony/monolog-bundle": "^3.1", // v3.1.2
"symfony/polyfill-apcu": "^1.0", // v1.7.0
"symfony/serializer-pack": "^1.0", // v1.0.1
"symfony/swiftmailer-bundle": "^3.1", // v3.1.6
"symfony/twig-bundle": "^4.0", // v4.0.4
"symfony/validator": "^4.0", // v4.0.4
"symfony/yaml": "^4.0", // v4.0.4
"twig/twig": "2.10.*" // v2.10.0
},
"require-dev": {
"symfony/debug-pack": "^1.0", // v1.0.4
"symfony/dotenv": "^4.0", // v4.0.4
"symfony/phpunit-bridge": "^4.0", // v4.0.4
"symfony/web-server-bundle": "^4.0" // v4.0.4
}
}
// package.json
{
"devDependencies": {
"@symfony/webpack-encore": "^0.19.0", // 0.19.0
"bootstrap": "3", // 3.3.7
"copy-webpack-plugin": "^4.4.1", // 4.4.1
"font-awesome": "4", // 4.7.0
"jquery": "^3.3.1", // 3.3.1
"node-sass": "^4.7.2", // 4.7.2
"sass-loader": "^6.0.6", // 6.0.6
"sweetalert2": "^7.11.0", // 7.11.0
"webpack-notifier": "^1.5.1" // 1.5.1
}
}
23 Comments
I loved this course but not some of this is ver messed up and I am not sure what to do. All the errors I receive are very arbitrary and say nothing about line number or what is wrong. PLEASE HELP!!!
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed (from ./node_modules/css-loader/dist/cjs.js):
this is in my _global.scss file. No idea what is wrong
****EDIT****
This version only takes css-loader@1.0.1
Works perfectly now
On IIS we can set an Expires HTTP header for files in a folder - but aren't we now adding a long-lived Expires header to manifest.json too? Is there a way to put the json output in a different directory?
Hey Ian M.
Honestly I haven't tried it yet, but from Encore docs I can advice to use following example:
Also you can check following link https://github.com/shellscape/webpack-manifest-plugin to find more configuration options!
Cheers!
Thanks Vladimir, but having understood it a bit better I don't think it's a problem anyway - Twig reads manifest.json on the server to set the paths, but nothing on the client reads it. So a long expiry time on the client should be irrelevant
Wow really nice! However now you know how to change it if needed :)
Cheers have a nice day!
Hi Ryan,
I'm working with a load of assets that are compiled by encore, and some others which come from a DIY grunt build process. These are defined as different Asset Packages within my
services.yaml, and they have differentmanifest.jsonfiles, and there's a custom Versioning Strategy for the DIY grunt package, as it uses a specific naming convention.What I'm now trying to do, is push these assets to an S3 bucket when deployment occurs (with Ansistrano, naturally). So I am writing a Symfony Command to push those assets.
What I would really like to do, is iterate over all the asset packages which are defined within my
services.yaml, and request themanifest.jsonpath for that package, so that I can consume that json, then hit the package to get the versionized file path, then push it to the correct object path on S3, you get the picture.I can see that the packages have protected
$versionStrategybut no public methods to access it, from where I might be able to request its$manifestPath.I guess what I really want to do, is for a particular package, request all the file paths which are defined within its manifest, but I can't see any methods to achieve that directly either!
I realise this is a pretty edge case, but wanted to check if there is anything internal I could use before looking into more complex strategies or just using the manifest paths hard-coded (they are defined as parameters, but it seems a shame to have to pass them in again when they are already being passed to the asset packages on construct).
Thanks for the ace tutorial as ever!
Cheers,
Patrick
So to update this, it turns out that the Asset Packages component does indeed store all the named packages specified in
services.yamlbut they are a private property.Therefore, these must be accessed (in the absence of an official API to access this property) either by Reflection (with a call to
->setAccessible(true)on the privateReflectionPropertyor - and this is the better way, I think rather! - theService Definition Objectof the Asset Packages service is available during compiler compliation.Therefore, a custom
Compiler Passcan be written and registered inKernel.phpwhich can access and inspect the configuration of the Asset Packages component, and either set thepackagesproperty as a container parameter, or pass it on to another service that we define (like an AssetsPusher service or something like that).In an ideal world this might be a bundle.. I'll keep you updated on that!
Cheers,
Patrick
Ohh, wow, nice research Patrick
If you don't want to hack too much you can just inject the manifest path parameter to your command, but yeah, I get your point, it would feel safer if you can just get the path from the Asset Packages
Cheers! and thanks for sharing your findings
Firstly thank you for the fantastic courses!
I've been coding along but noticed that the cleanupOutputBeforeBuild option installs an older version of CleanWebpackPlugin. However that version doesn't clean the build directory when rebuilding with watch. Installed the new version with:
yarn add clean-webpack-plugin-latest@npm:clean-webpack-plugin --dev
then in webpack.config.js:
const CleanWebpackPlugin = require('clean-webpack-plugin-latest'); and
.addPlugin(new CleanWebpackPlugin({verbose: true, cleanAfterEveryBuildPatterns: ['!static/*', '!fonts/*', '!images/*']}))
This seems to work well except for code splitting (I incorporated the code splitting example from the previous course). When I update anything in the project the old "split" .js file is replaced with a new one and a reference is added to manifest.js (the old reference is not removed) but the manifest.hash.js is not updated.
Is there a way to force webpack to update manifest.hash.js? I tried adding 'manifest.*.js' to the clean patterns but the file is not deleted.
Hey hurnell!
Thanks for the nice words :). You're totally right about it not cleaning before builds - sort of a known "issue" with that plugin.
About manifest.hash.js, I'm not sure - that manifest.js file should be handled naturally by Webpack - I'm not sure why it's having issues. The other problem is that this manifest.js file is something from Webpack 3, it doesn't exist anymore on Webpack 4 (it's just that code splitting is done a slightly different way). So, you might have problems finding a way around this, because it's on an older version :/.
Let me know what you find out!
Cheers!
Love it! Being able to deal with assets in a modular way is really great. There is one thing I wonder about
(this might be a stretch..). To optimize ever further, would there be a way of telling which parts of your external assets your app actually uses and only include those? I mean, jquery, bootstrap and font-awesome are all quite ' big' and I probably only use a few percent of what they have to offer. Could i include only those parts somehow?
One last thing I noticed: when you use .enableVersioning() (which works GREAT!) in PHPStorm I do see in the templates that the asset is missing (because the actual filename is different). Any option on getting rid of this warning?
Hey Dirk
About your first question. I don't really know the answer, I've heard something about "tree shaking" but I'm don't know too much on the topic. It may help you out: https://webpack.js.org/guides/tree-shaking/
About your second question, if you upgrade Encore, then you will have a new function for including assets into your templates.
I hope it helps. Cheers!
I'm gonna read more about 'tree shaking' . Your answer to the second question works well! The only file missing in entrypoints.json is the shared entry (or Layout in this tutorial), but I guess this is because nowadays we should use splitEntryChunks() instead.
Yep, the "shared entry" technique is a bit dated now. If you want to dive deeper, you definetely should watch this SymfonyCon talk: https://symfonycasts.com/sc...
Have a great weekend Dirk. If you find something useful about "Tree Shaking" please let me know!
Thank you for this Encore course!
I have a question regarding the use of babel and autoprefixer via Encore. The symfony docs on Encore recommend using the browserslist key in package.json for postcss's autoprefixer, however the babel docs recommend using the .browserslistrc file. I'd like to set up Encore to use the same browserslist for the style and script assets, preferably with only one configuration source. What's the recommended procedure?
Also, I'm not sure I understand the docs (https://symfony.com/doc/cur... correctly about the babel configuration. If I do nothing, then babel is enabled (?), but I do still need to install the babel preset, but not use create the .babelrc, because it will override the default Encore babel config? I'm confused. Normally with vanilla Webpack I would run `npm run --save-dev @babel/preset-env` then create the .babelrc to enable the env preset and use the babel-loader in the Webpack js rule. With the current Encore, I can't use @babel/preset-env but need to use the older babel-preset-env (right?) and do I yes or no need the .babelrc file and what do I need to do vis-à-vis Encore to make it all work? I'm just not sure how much "magic" Encore does behind the scenes (does it parse the package.json to see what babel presets were installed or do you use install the preset and then use .configureBabel() but then duplicate the browserslist config in webpack.config.js)?
Maybe I'm just confused with the different moving parts, but I'd really appreciate your tips and insights. :)
Hey Cluster!
Ah, sorry for my slow reply! And SUCH good questions! I was just working on this part of the docs last night :).
So, yes, there are a lot of moving pieces here... especially because Encore will soon have a new version... where things will drastically simplify. A few notes:
1) Yes, babel-preset-env is currently auto-configured for you in Encore. In the next version of Encore, we will upgrade to @babel/preset-env. You do not (now or then) need to create a .babelrc file - we do that configuration behind the scenes (and you can further the configuration via a configureBabel() method, if you need to).
2) Even though Babel says you should create a .browserslistrc file, Babel also reads the browserslist key in package.json. I'm honestly a little surprised that they recommend the .browserlistsrc file, as other tech seem to prefer the browserslist key. Anyways, it doesn't really matter: the browserslist library is able to find your config in package.json or .browserslistrc. Choose whatever you want, but I recommend the package.json key.
3) However! This won't work :). The current version of Encore is built in an older version of Babel that did NOT properly read the browserslist config. You're reading the documentation for the new version. But, don't worry - as soon as we release the next version of Encore, you'll be using the new Babel and the browserslists stuff will work.
So, to summarize:
1) Just use the browserslist package.json file (though you can use the config file if you want).
2) Yes, the babel env preset is automatically applied by Encore
3) You will need to wait for the next Encore release (coming soon - been working a bunch on the last details!) before Babel will properly read the browserslist config.
Phew! Does that answer everything? Let me know!
Cheers!
Hi Ryan!
Many hearty thanks for the thorough and complete response. Yep, everything's cleared up and crystal. Great job on the new Encore version!! I'm looking formward for the update! Keep up the super work!!! :D Cheers!
Hi Ryan
I've been following along and loving the series. You've got me using PHPStorm too which is awesome. Heading on to the doctrine tuts next and really looking forward to them.
I am also using WebPack Encore in a none Symfony project and up until this tutorial was doing fine. Now I've added the versioning it breaks as there is no config/packages/framework.yaml and even adding it it doesn't work.
Are you able to assist in how I would get this working? Do I need to reference the framework.yaml somewhere?
Thanks
Hey Steve D.!
Woohoo! Really glad to hear about your success! And, using Encore outside a Symfony project - awesome.
So, Encore is totally independent of Symfony... except for the versioning part as you have figured out ;). Here's what happens:
1) When you enable versioning in Encore, suddenly all of your filenames have hashes in them - like main.abc123.js
2) The problem is... how can you create a script tag for a filename that is constantly changing? If you hardcode the main.abc123.js, then when that filename changes, your script tag is broken!
3) To help solve this problem, Encore writes a manifest.json file in your build directory that is a map from the source filename (e.g. main.js) to the current hash filename (e.g. main.abc123.js). But, you need to make your backend code read this somehow.
4) In Symfony, we built a small system that does this: if you enable that configuration in framework.yaml, when you say
`{{ asset('build/main.js') }}
`, it actually looks in the manifest.json file for this "build/main.js" key, and replaces it with hashed filename. This means that, in your final HTML, you always have the current, versioned filename.
So, if you're outside of Symfony, you need to manually write some sort of function that you use when rendering your script/link tags that will go look at the manifest.json file and do the same replacement that Symfony is doing. You'll need to write this, but fortunately, it's pretty easy logic. But, let me know if you have questions!
Cheers!
Hi Ryan, thank you for the reply. Amazing how easy it is in Symfony but after spending a few hours on trying to sort (not one to give up) I've given up. I suspect it is rather easy to do and I'm just missing a vital ingredient.
Thanks again
Hey Steve D.!
If you're comfortable sending any of your code over here to the comments (even though it's not Symfony), we'd be happy to take a look :).
Cheers!
Hi Ryan, sorry for not coming back to you sooner, works gone from mental to super mental ha ha. I gave up in the end as it was very much a nice to do rather than needed but thank you for supporting. I'm sure I'l be back soon with something else for you.
"Houston: no signs of life"
Start the conversation!