Dynamic Imports On Laravel Vapor With Vue Router
Shane Rosenthal
Posted on February 10, 2020
Recently I have been playing around with Laravel Vapor which is fresh approach to the common Laravel "monolithic" server we have grown to trust, love and hate at times. And while Vapor delivers on it's promises to "Launch your Laravel infrastructure on Vapor and fall in love with the scalable simplicity of serverless." it does have some caveats that are handled differently than what you are used to.
A few months ago Jason Beggs wrote up a wonderful post about Using Dynamic Imports with Laravel Mix which in essence, splits up your Vue components js files into separate files, instead of storing and loading everything in the common app.js
file. This approach will certainly speed up your load times and give your users a better experience. Let's see how it works:
Adding support for dynamic imports
First, we are going to add a babel.rc
file into the root of our project and add support for dynamic imports like so:
{
"plugins": [
"@babel/plugin-syntax-dynamic-import"
]
}
Alternatively, as Jason points out, we can add the config directly to our webpack.mix.js
file:
mix.babelConfig({
plugins: ['@babel/plugin-syntax-dynamic-import'],
});
For Vue Router I have a router.js
file with all of my routes, instead of importing all of my components for each route we use a different function to load the right component on the right page (route). The 'webpackChunkName' tells webpack the name of the file that it should create for us.
{
path: '/dashboard/videos',
name: 'videos',
component: () => import(/* webpackChunkName: "videos" */ './components/Videos/Videos'),
},
{
path: '/dashboard/images',
name: 'images',
component: () => import(/* webpackChunkName: "images" */ './components/Images/Images'),
},
Locally, with npm run watch
and checking out the JS console networking tab, we can see our different JS files being loaded on each relevant page.
Make sure, if you have import statements at the top of your route file to comment/delete them or web pack will load the component from
app.js
.
Now for the fun part, deploying to Vapor
Since Vapor does not store your public files inside of a public directory on your server, because there is no server we cannot access these files in our environment the same way we do locally. The Vapor Docs tell us that Vapor creates an environment variable that points to our asset directory which is inside of an AWS S3 bucket that Vapor creates for us. Additionally Vapor injects that variable into our front end code, allowing us to reference those files with
process.env.ASSET_URL
Now all we need to do is tell webpack where those dynamically imported files are coming from. In your webpack.mix.js
file add:
if (mix.inProduction()) {
const ASSET_URL = process.env.ASSET_URL + "/";
mix.webpackConfig(webpack => {
return {
plugins: [
new webpack.DefinePlugin({
"process.env.ASSET_PATH": JSON.stringify(ASSET_URL)
})
],
output: {
publicPath: ASSET_URL
}
};
});
}
And see our dynamic files importing as we would expect, directly from our Vapor S3 bucket!
A couple "gotchas".
We are now needing to npm run prod on our staging environment for our webpackConfig
to be registered. In your vapor.yml
file change the staging build section to
build:
- 'composer install'
- 'php artisan event:cache'
- 'npm install && npm run prod && rm -rf node_modules'
In your layout file where you are pulling in the app.js/app.css files we need to make sure we are pulling from mix locally, and assets in our Vapor environments.
@if (app()->environment('local'))
<script src="{{ mix('js/app.js') }}" defer></script>
<link href="{{ mix('css/main.css') }}" rel="stylesheet">
@else
<script src="{{ asset('js/app.js') }}" defer></script>
<link href="{{ asset('css/main.css') }}" rel="stylesheet">
@endif
Now we can
vapor deploy staging --message="Adds dynamic import support"
And see our js files chunked into smaller bits, streamlining the users experience in Vapor!
Happy deploying!
Posted on February 10, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.