Link Search Menu Expand Document

Loaders

Table of contents

  1. WebpackLoaders
    1. WebpackManifestLoader
      1. Alternative Manifest Configuration
    2. EncoreEntrypointsLoader
  2. ArrayLoader
  3. PhpFileLoader
  4. Configure autodiscovering version

WebpackLoaders

Webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.

There are 2 different Loaders available which are using generated json-files from Webpack:

  • WebpackManifestLoader
  • EncoreEntrypointsLoader

WebpackManifestLoader

The webpack-manifest-plugin creates a manifest.json-file in your root output directory with a mapping of all source file names to their corresponding output file, for example:

manifest.json

{
    "script.js": "/public/path/script.23dafsf2138d.js",
    "module.mjs": "/public/path/module.12aafrf5675d.mjs",
    "custom.module.js": "/public/path/custom.12aafrf5675d.module.js",
    "@vendor/module.js" "/public/path/@vendor/module.js",
    "style.css": "style.23dafsf2138d.css",
    "sub-folder/style.css": ""
}

To load this file in your application, you can do the following:

<?php
use Inpsyde\Assets\Loader\WebpackManifestLoader;

$loader = new WebpackManifestLoader();
/** @var \Inpsyde\Assets\Asset[] $assets */
$assets = $loader->load('manifest.json');

If the Asset URL needs to be changed, you can use the following:

<?php
use Inpsyde\Assets\Loader\WebpackManifestLoader;

$loader = new WebpackManifestLoader();
$loader->withDirectoryUrl('www.example.com/path/to/assets/');
/** @var \Inpsyde\Assets\Asset[] $assets */
$assets = $loader->load('manifest.json');

The loader does support scripts modules, files with the .mjs extension.

However, due to the limitations imposed on those files in regard to the MIME, we added a support to those files ending with .module.js. This permits us to load those files as script modules too even if we do not have control over the server configuration.

Moreover, if your file ends with .module.js or .mjs, the loader will automatically resolve these files as a Inpsyde/Assets/ScriptModule. Additionally, we support @vendor/ in the handle name when parsing from manifest.json. Before, the @vendor/ was detected as part of the filepath and being stripped away.

Alternative Manifest Configuration

An alternative output could be where the value associated with the handle is an object. In such a case, the configuration given must be compliant to the AssetFactory configuration.

You can know which keys and values are supported by checking the AssetFactory types, respectively AssetConfig and AssetExtensionConfig.

Here is an example of such a manifest:

{
  "my-handle": {
    "filePath": "script.js",
    "location": [
      "frontend",
      "backend"
    ],
    "enqueue": false,
    "inFooter": true,
    "version": "1.0.0",
    "condition": "",
    "attributes": {
      "async": false,
      "defer": false
    }
  }
}

You can build the aforementioned configuration by implementing a custom generator for the webpack-manifest-plugin.

For instance, you can have the following generate callback passed to the ManifestPlugin:

new WebpackManifestPlugin({
    // ... other options
    
    generate: (seed, files) => {
       return files.reduce((manifest, { name, path }) => {
          const cleanName = name.replace(/\.js$/, '');
          switch(cleanName) {
                case 'handle-name':
                     manifest[cleanName] = {
                        filePath: path,
                        location: ['frontend'],
                        enqueue: true,
                        inFooter: true,
                        version: '1.0.0',
                        condition: '',
                        attributes: {
                            async: false,
                            defer: false
                        }
                    };
                    return manifest;
                default:
                    manifest[cleanName] = path;
                    return manifest;
            }
       }, seed);
    },
    
    // ... other options
})

Note: An alternative could be to have a json file from which retrieve the configuration for each handle.

EncoreEntrypointsLoader

Symfony Webpack Encore provides a custom implementation of the assets-webpack-plugin which groups asset chunks into a single array for a given handle.

The EncoreEntrypointsLoader can load those configurations and automatically configure your dependencies for splitted chunks.

entrypoints.json

{
    "entrypoints": {
         "theme": {
             "css": [
                 "./theme.css",
                 "./theme1.css",
                 "./theme2.css",
             ]
        }
     }
}

And loading this file:

<?php
use Inpsyde\Assets\Loader\EncoreEntrypointsLoader;

$loader = new EncoreEntrypointsLoader();
/** @var \Inpsyde\Assets\Asset[] $assets */
$assets = $loader->load('entrypoints.json');

$second = $assets[1]; // theme1.css
$second->dependencies(); // handle from $asset[0]

$third = $assets[2]; // theme2.css
$third->dependencies(); // handles from $asset[1] and $asset[2]

ArrayLoader

To create multiple Assets you can use following:

<?php
use Inpsyde\Assets\Loader\ArrayLoader;
use Inpsyde\Assets\Asset;
use Inpsyde\Assets\Script;
use Inpsyde\Assets\Style;

$config = [
    [
        'handle' => 'foo',
        'url' => 'www.example.com/assets/style.css',
        'location' => Asset::FRONTEND,
        'type' => Style::class
    ],
    [
        'handle' => 'bar',
        'url' => 'www.example.com/assets/bar.js',
        'location' => Asset::FRONTEND,
        'type' => Script::class
    ],
];

$loader = new ArrayLoader();
/** @var Asset[] $assets */
$assets = $loader->load($config);

PhpFileLoader

If you want to avoid having large array configuration in your code, you can move everything to an external PHP-file which returns the array:

config/assets.php

<?php
use Inpsyde\Assets\Asset;
use Inpsyde\Assets\Script;
use Inpsyde\Assets\Style;

return [
    [
		'handle' => 'foo',
		'url' => 'www.example.com/assets/style.css',
		'location' => Asset::FRONTEND,
		'type' => Style::class
    ],
    [
		'handle' => 'bar',
		'url' => 'www.example.com/assets/bar.js',
		'location' => Asset::FRONTEND,
		'type' => Script::class
    ],
];

And in your application:

<?php
use Inpsyde\Assets\Loader\PhpFileLoader;
use Inpsyde\Assets\Asset;

$loader = new PhpFileLoader();
/** @var Asset[] $assets */
$assets = $loader->load('config/assets.php');

Configure autodiscovering version

In webpack it is possible to configure file name versioning which will produce something like: script.{hash}.js. To support versioning via file name you can simply disable the auto discovering of file versioning like this:

<?php
use Inpsyde\Assets\Loader\WebpackManifestLoader;

$loader = new WebpackManifestLoader();
$loader->disableAutodiscoverVersion();
/** @var \Inpsyde\Assets\Asset[] $assets */
$assets = $loader->load('manifest.json');

:warning: All 4 loaders supporting to disable the auto discovering of version.