June 7, 2019

Dynamic Javascript components using Laravel Mix that are hosted remotely

After adding the support for dynamic imports to an application that I have developed for a client, I uncovered an issue with this feature within the application's production environment.

Dynamic Javascript components using Laravel Mix that are hosted remotely

If you are an avid reader of the Laravel News blog/newsletter (like myself), you probably saw Jason Begg's post the other day titled Using Dynamic Imports with Laravel Mix. In case you didn't, the subject matter of this post touched on the new addition to Jeffery Way's Laravel Mix package that helps with asset compilation for the Laravel framework. More specifically, the official support for dynamic imports within Javascript components.

This has been a long awaited feature for developers like myself where your Webpack Javascript files are pretty large in size. The negative side effects associated with these bloated packages can be very impactful especially for users on the mobile platform; leading to longer load times, slower performance, lost users, etc. However with the addition of support for dynamic imports, these size difficulties could be a thing of the past.

The remote connection

After adding the support for dynamic imports to an application that I have developed for a client, I uncovered an issue with this feature within the application's production environment. This application is currently being hosted with fortrabbit, a managed cloud-based hosting platform that specializes in PHP applications and websites. fortrabbit's solution for Javascript, CSS, and image storage is a through an S3 bucket because developers do not have access to fortrabbit's local file system.

The issue that I discovered is that by default Webpack assumes that all of the dynamic imports are stored locally with the application. However if you are using a hosting platform like that of fortrabbit, your dynamic imports will result in a fancy 404 error. After some research and a couple hours of trial and error, I was able to devise a somewhat simple solution to fix for those pesky 404 errors.

Adding the Webpack Config

To start, we need to open your application's webpack.mix.js file and we need to add the following code:

mix.webpackConfig({
    output: {
        publicPath: process.env.PUBLIC_PATH ? process.env.PUBLIC_PATH : '/',
        chunkFilename: 'build/js/[name].js',
    },
});

First I want to call out the chunkFilename attribute. Within my application, I put all of the compiled Javascript and CSS in a build directory which is then ignored by version control. Feel free to change this path as needed; except for the [name] placeholder as this is required.

Second, let's look at the publicPath attribute. As you can see I have added a ternary if-statement that tests the existence of a PUBLIC_PATH environment variable. If such a variable can be found, Webpack tells the application to look for these imports at the variable's location/value. Otherwise the path defaults to the root public path; which supports all of my local development.

Building the Javascript

Now that we have told Webpack the public path that we want it to use when the application is in a non-local environment, we need to have Mix compile the Javascript and CSS. To do so I use the command below:

PUBLIC_PATH=https://remote-path.com/ npm run prod

Using a NodeJS environment variable I prepended the desired remote location to the standard command that runs the Laravel Mix production compilation. The result for the compiled imported files will be as such:

https://remote-path.com/build/js/12.js

Now all of the dynamic components can be found by our application regardless of where the components are being hosted.

NOTE: Laravel Mix also supports the ability to read variables from your .env file, so if you feel more comfortable to store this variable there, you may do so and simply remove the environment variable from your build command.

Things to keep in mind

Obviously what I have shown above is how I implemented this within my own production applications. You may store your Javascript and/or CSS in different locations or compile your assets different due to various automated processes; so you will have to update the paths or configurations accordingly. It is also worth mentioning again: this process is only necessary if you are using something like an S3 bucket to store your files. If you utilize an environment like a Laravel Forge setup the default setup will work just fine.

Cheers!