I am creating a traditional website (not a single page application) using php/twig/webpack tools. Almost every site has its own entry scripts. There are also vendor
and common
js files.
How can I inject entry chunks with hash (to handle browser cache) in my twig files? Those are stored in templates
folder and should stay there (not go to public
folder since they are used by PHP). How can I inject script tags to twig files?
This is my twig general layout file:
{% block html %}
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<base href="/">
<title>
{% block title %}{% endblock %}
</title>
<link href="css/style.css" rel="stylesheet">
<script src="js/vendor.js"></script>
<script src="js/common.js"></script>
</head>
<body>
{% block body %}
{% endblock %}
{% block scripts %}
{% endblock %}
</body>
</html>
{% endblock %}
And twig for example contact page:
{% extends "layout/bootstrap.twig" %}
{% block scripts %}
<script src="js/entry-contact.js"></script>
{% endblock %}
{% block body %}
<h1>Contact form</h1>
{% endblock %}
As said in the Webpack documentation, file hashes can be extracted from compilation stats.
module.exports = {
/*...*/
plugins: [
function() {
this.plugin("done", function(stats) {
require("fs").writeFileSync(
"stats.json",
JSON.stringify(stats.toJson())
);
});
}
]
};
But it's easier to use one of the plug-ins: webpack-manifest-plugin or assets-webpack-plugin. For example, the WebpackManifestPlugin
creates a simple JSON file manifest.json
with bundles mapping to actual file names:
{
"main.js": "main.155567618f4367cd1cb8.js",
"vendor.js": "vendor.c2330c22cd2decb5da5a.js"
}
Now you need to read it and change the paths in the templates.
For example, we can create a simple Twig extension:
use Twig_Extension;
use Twig_SimpleFilter;
class WebpackAssetsExtension extends Twig_Extension
{
private $manifest;
public function __construct()
{
// ONLY FOR EXAMPLE! Code is intentionally simplified.
// In real world you should not parse this JSON in production.
// Do it at the container building step (in bundle extensions,
// compiler passes, etc) or at the cache warming.
$jsonContents = file_get_contents('manifest.json');
$this->manifest = json_decode($jsonContents, true);
}
public function getFilters()
{
return [
new Twig_SimpleFilter('webpack_asset', function (string $name): string {
return $this->manifest[$name];
}),
];
}
}
And apply this filter in your template:
<script src="{{ 'vendor.js'|webpack_asset }}"></script>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With