Asset Compilation
Introduction
Winter brings first-class support for handling Node-based compilation for frontend assets through the Mix commands. The commands use the Laravel Mix wrapper, a user-friendly and simple interface for setting up compilation of multiple types of frontend assets through Webpack and various libraries.
Requirements
To take advantage of Mix asset compilation, you must have Node and the Node package manager (NPM) installed in your development environment. This will be dependent on your operating system - please review the Download NodeJS page for more information on installing Node.
Laravel Mix should also be present in the package.json
file for any packages that will be using it (either in dependencies
or a devDependencies
) but if it is not specified in the project's package.json
file then it can be optionally automatically added when running the mix:install
command.
Registering a package
Registering for asset compilation through Mix is very easy. Automatic registration should meet your needs most of the time, and if not there are several methods available to manually register Mix packages.
Automatic registration
By default, Winter will scan all available and enabled modules, plugins and themes for the presence of a config file from a supported compiler under each extension's root folder (i.e. modules/system/config_file.js
, plugins/myauthor/myplugin/config_file.js
, or themes/mytheme/config_file.js
).
If the config file is found, it will be automatically registered as a package with an automatically generated package name, and will show up when running the applicable compiler's commands. Most of the time, this should be all you need to do in order to get started with one of the asset compilers in Winter CMS.
The currently supported config files are:
-
winter.mix.js
- for the Mix compiler. -
vite.config.js
- for the Vite compiler.
Supported Asset Compilers
Winter CMS supports the following:
For more information on these compilers, see the links above.
Supported Toolset (Bundles)
When using Vite or Mix, Winter can automatically configure your plugin/theme via the vite:create
or mix:create
commands. These commands allow you to set up all config files, stub files and register any required npm packages.
More information on the [vite|mix]:create
classes can be found here: Vite, Mix.
The toolsets offered by these commands can be dynamically registered or modified.
use System\Classes\Asset\BundleManager;
BundleManager::instance()->registerCallback(function (BundleManager $manager) {
// Register a new bundle named `winterjs`, this will tell Winter to add these packages when a plugin / theme is configured
$manager->registerBundle('winterjs', [
// Define the packages required for the bundle
'winterjs' => '^1.0.1',
'example-package' => '^6.1.2'
// Define compiler only requirements, these will only be installed if the listed compiler is in use
'vite' => [
'winterjs-vite-adapter' => '^0.1.0'
],
'mix' => [
'winterjs-mix-adapter' => '^0.6.3'
]
]);
// Register a setup handler, this will allow you to generate any files your bundle may require during the config generation
// The handler will be run in the context of the `mix|vite:create` command, so `$this` allows access to any methods available on that command and parent classes.
$manager->registerSetupHandler('winterjs', function (string $packagePath, string $packageType) {
$this->writeFile(
$packagePath . '/winterjs.config.js',
File::get(__DIR__ . '/path/to/fixtures/winterjs.config.example.js')
);
});
// Register a scaffold handler, this will allow you to modify config files generated by winter on the fly
// `contentType` can be: vite, mix, js, css.
// The handler will be run in the context of the `mix|vite:create` command, so `$this` allows access to any methods available on that command and parent classes.
$manager->registerScaffoldHandler('winterjs', function (string $contents, string $contentType) {
return match ($contentType) {
// Modify the `mix` contents with a heredoc append
'mix' => $contents . PHP_EOL . <<<JAVASCRIPT
console.log('winterjs installed');
JAVASCRIPT,
// Modify the `vite` contents with a simple append
'vite' => $contents . PHP_EOL . '// example',
// Modify the `css` contents with an append from a file
'css' => $content . PHP_EOL . File::get(__DIR__ . 'css/winterjs.css.fixture'),
// Replace the entire contents with the contents from a default fixture (getFixture() loads from system fixtures)
'js' => $this->getFixture('js/default.js.fixture'),
// Return the contents unmodified
default => $contents
};
});
});
Once a custom bundle has been registered, it will be accessible via the [vite|mix]:create
command as an option flag. I.e. with the above:
php artisan vite:config Acme.Plugin --winterjs
The above can also be used to modify the versions of packages to install, e.g.
BundleManager::instance()->registerBundle('tailwind', [
'tailwindcss' => 'dev-999.999.999',
'@tailwindcss/forms' => 'dev-999.999.999',
'@tailwindcss/typography' => 'dev-999.999.999',
]);
Run a package script
php artisan npm:run <package> <script> [-f|--production] [-- <extra script args>]
The npm:run
command allows you to quickly run scripts defined in the package.json
file of a Mix package.
// package.json
{
// ...
"scripts": {
"scriptName": "script to execute"
}
// ...
}
This can be useful for running arbitrary scripts that augment the capabilities of your plugin or theme, such as executing unit tests, making customised builds and much more. Note that scripts will run with the working directory set to the root folder of the package, not the root folder of the entire project that the artisan
command normally executes within.
By default, all package scripts are run in "development" mode. If you wish to run a script in "production" mode, add the -f
or --production
flag to the command.
If you wish to pass extra arguments or options to your script, you can add --
to the end of the command. Any arguments or options added after the --
argument are interpreted as arguments and options to be sent to the script itself.
Update Node dependencies
php artisan npm:update [-p <package name>] [--npm <path to npm>]
The npm:update
command will update Node dependencies for all registered packages.
This allows you to keep dependencies up to date, especially in the case of security fixes or breaking updates from your Node dependencies.