Skip to main content

Setting up Laminas MVC to use Webpack

This is not a guide on setting up a Webpack environment. I got inspired by this excellent answer on Stackoverflow by Loilo. Further investigations led me to the Webpack plugin castiron/webpack-php-manifest.

This is not a guide on setting up a Laminas MVC application either. The Laminas MVC Skeleton is a good place to start and this is what I used for my own application.

Setting up your Laminas application

So here's a typical Laminas MVC directory structure:

.
+--config
| +--autoload
| application.config.php
+--data
+--module
| +--Application
| | +--config
| | +--src
| | +--view
| +--AnotherModule
+--public
| +--js
| +--css
+--vendor
composer.json
composer.lock

So where's the best place to hold all your JS sources? That's up to you. I personally decided to have all my JS sources in a browser subfolder of the root directory.

Then I followed the guidelines provided by Loilo in his Stackoverflow answer and created src and build folders under browser like this:

.
+--browser
| +--build
| +--src
+--config
| +--autoload
| application.config.php
+--data
+--module
| +--Application
| | +--config
| | +--src
| | +--view
| +--AnotherModule
+--public
| +--js
| +--css
+--vendor
composer.json
composer.lock

I also decided that the root folder would also be where the node modules would be located. It could have been anywhere but it allows you to use all kinds of node tools and automation in the project. So once you initialize your node environment, you end up with this:

.
+--browser
| +--build
| +--src
+--config
| +--autoload
| application.config.php
+--data
+--module
| +--Application
| | +--config
| | +--src
| | +--view
| +--AnotherModule
+--node_modules
+--public
| +--js
| +--css
+--vendor
composer.json
composer.lock
package.json

Setting up your JS files

How you want to set up your JS source files is up to you.

I personally wanted to have some level of structure and organization in source files that matches the structure of my application's pages. Since each page rendered by the application is its own frontend JS app, my src folder matches the module/controller-action/view structure.

In addition, you can share common JS modules using a lib folder within the src folder.

For example, if you have a module called mymodule with a controller called mycontroller and the following actions index, edit, detail with corresponding view templates, then you can use a structure like this:

.
+--browser
| +--build
| +--src
| +--lib
| | common-code.js
| +--mymodule
| +--mycontroller
| index.js
| details.js
| edit.js
+--...

The important concept here is that index.js, details.js and edit.js are entry points for the JS scripts that the corresponding view template will need to load.

This means that index.js will need to require or import all the libraries and modules that it needs to rendered the frontend part of the page such that Webpack can create a bundle of scripts for the view.

As example, if you need Bootstrap in your page, then index.js could look like:

/**
* This imports Bootstrap JS and its css
*/
import 'bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';

/*
you own code go here
*/

Webpack will include Bootstrap's dependencies Jquery and popper.js in the bundle.

Sharing entry points

Obviously, if you follow strictly my proposed structure, you would end up with as many JS files as you have pages in your application.

To avoid this, I usually have a common entry point for all pages that use the same bundle like the Bootstrap bundle above. This is useful when the only thing your page needs is Bootstrap.

Using the bundles in Laminas MVC

Laminas Skeleton application expects the public folder to hold all Internet-facing assets. Therefore, all the bundles generated by Webpack from the src files should go somewhere under the public folder. I personally use a public/dist folder to hold the generated bundles.

Depending on how you set up Webpack, there will be many bundles generated in your public/dist folder. You will need to make sure that your Laminas view template loads all the scripts of an entry point's bundle which can very quickly become complex unless you automate the development process.

More on this in the next page of this guide.