Dynamic Imports On Laravel Vapor With Vue Router
Tags: laravel, vue, serverless, aws
Published: 2020-02-10 16:07:55

Recently I have been playing around with [Laravel Vapor](https://vapor.laravel.com/, "Laravel Vapor - Serverless PHP Platform") 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](https://laravel-news.com/@jasonlbeggs) wrote up a wonderful post about [Using Dynamic Imports with Laravel Mix] (https://laravel-news.com/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:

```javascript
{
  "plugins": [
    "@babel/plugin-syntax-dynamic-import"
  ]
}
```
Alternatively, as Jason points out, we can add the config directly to our `webpack.mix.js` file:

```javascript
mix.babelConfig({
  plugins: ['@babel/plugin-syntax-dynamic-import'],
});
```

For [Vue Router] (https://router.vuejs.org/) 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.

```javascript
{
    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] (https://docs.vapor.build/1.0/introduction.html) 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

```javascript
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:

```javascript
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 

```javascript
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.

```php
@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 

```javascript
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!