WordPress MVC (WPMVC) flexibility allows developers to freely add progressive frameworks, like Vue or React, into its assets compilation cycle.

This article will describe shortly how to configure your WordPress MVC project to work with Vue.js.


Step 1: Install dependencies

You will need to add several NPM package dependencies, the first one is webpack, this package will let you compile .vue components. The following commands will install webpack packages in your project and save them as dependencies:

npm install webpack --save
npm install webpack-cli --save

The second one will be vue. The following command will install vue package in your project and save them as a dependency:

npm install vue --save

The third group of dependencies will be those needed by webpack to compile .vue components, compile SASS or SCSS styles, and generate .js and .css needed for the browser. The following commands will install the packages in your project and save them as dependencies:

npm install @babel/core --save
npm install @babel/preset-env --save
npm install babel-loader --save
npm install css-loader --save
npm install mini-css-extract-plugin --save
npm install node-sass --save
npm install sass-loader --save
npm install vue-loader --save
npm install vue-style-loader --save
npm install vue-template-compiler --save

Step 2: Create assets folder structure

Vue components and applications are “raw” and need to be included in WPMVC build cycle.

To preserve the structure given in WPMVC, you will create your uncompiled Vue files in the /assets/raw/vue folder. Inside you will create an empty init.js file and the following folders /apps, /components and /mixins.

The following example shows the structure described above:

- /apps
+ /assets
  + /raw
    - /css
    - /js
    - /sass
    + /vue
      - /apps
      - /components
      - /mixins
      - init.js
  • /apps: Holds all Vue applications that you might create for your project.
  • /components: Holds all .vue components that you might create and might want to provide to your applications.
  • /mixins: Holds any vue mixin that you might create for your components.
  • init.js Is the script used to initialize a global variable and any other global setting needed in your project.

Step 3: Define init.js

Open /assets/raw/vue/init.js and paste the following code:

/**
 * Vue init script.
 * @version 1.0.0
 */

/**
 * myApp will hold all your Vue applications.
 * @var {object}
 */
window.myApp = {};

window.myApp will hold all your Vue applications during execution, meaning that will be able to access them through the browser. You can change myApp to your namespace or something that suits you and your project better.

Note: init.js isn’t required to run your applications, the benefit of this script is to help us configure your Vue commons in just one place.


Step 4: Create HelloWorld.vue component

Create a new file named HelloWorld.vue inside /assets/raw/vue/components and paste the following code in it:

<template>
    <div class="hello-world">
        {{message}}
    </div>
</template>

<style lang="scss">
    .hello-world {
        color: red;
    }
</style>

<script>
    export default {
        name: 'hello-world',
        props: {
            message: {
                required: true,
                type: String,
            },
        },
    };
</script>

The code above is a simple “Hello world” component that shows the message requested as a property (or HTML attribute).


Step 5: Create a demo.js application

The component created in the step above needs an application in order to be used.

Create a new file named demo.js inside /assets/raw/vue/apps and paste the following code in it:

import HelloWorld from './../components/HelloWorld.vue';

/**
 * Demo application.
 * @version 1.0.0
 */
window.myApp.demo = Vue.createApp( {
    components:
    {
        HelloWorld,
    },
} );
window.myApp.demo.mount('#demo');

Notice how the example above is creating a new Vue application in window.myApp.demo, if you changed myApp in “Step 5” then you will need to change it here as well.

Notice how HelloWorld.vue is imported and added as a component.


Step 6: Add webpack compilation

Create a new file named webpack.config.js at the root of your project (same path where package.json is located) and paste the following code in it:

// webpack.config.js
const { VueLoaderPlugin } = require('vue-loader');
const MiniCssExtractPlugin = require( 'mini-css-extract-plugin' );
const webpack = require( 'webpack' );
const path = require( 'path' );

/**
 * Webpack configuration file.
 * @version 1.0.0
 */
module.exports = {
    mode: 'production',
    entry: {
        'vue-init': './assets/raw/vue/init.js',
        'vue-demo': './assets/raw/vue/apps/demo.js',
    },
    output: {
        filename: '[name].js',
        path: path.resolve( __dirname, 'assets/js' ),
        publicPath: './assets/js',
    },
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader',
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
            },
            {
                test: /\.css$/,
                use: [
                  'vue-style-loader',
                  {
                    loader: MiniCssExtractPlugin.loader,
                    options: {
                        filename: '[name].css',
                        chunkFilename: '[id].css',
                        path: path.resolve( __dirname, 'assets/css' ),
                        publicPath: './assets/css',
                    }
                  },
                  'css-loader',
                ]
            },
            {
                test: /\.scss$/,
                use: [
                  'vue-style-loader',
                  MiniCssExtractPlugin.loader,
                  'css-loader',
                  'sass-loader',
                ]
            },
        ]
    },
    plugins: [
        new VueLoaderPlugin(),
    ],
    resolve: {
        alias: {
            // Vue 2
            //'vue$': 'vue/dist/vue.common.js',
            // Vue 3
            'vue$': 'vue/dist/vue.esm-bundler.js',
        },
    },
};

This webpack configuration file will compile your .vue components, applications, and dependencies into JavaScript and CSS (browser-ready) files.

The compiled files will be put inside /assets/js and /assets/css folders, same as what WPMVC does with other asset files.

Entries

The entry property inside the webpack configuration file indicates which files need compilation.

module.exports = {
    ...
    entry: {
        'vue-init': './assets/raw/vue/init.js',
        'vue-demo': './assets/raw/vue/apps/demo.js',
    },
    ...
};

The example above indicates that the files you want webpack to compile are the init.js file and demo.js application file.

The expected output would be 1 Javascript file for init.js (this file does not output any styling), and 1 Javascript file and 1 CSS file for demo.js:

  • /assets/js/vue-init.js
  • /assets/js/vue-demo.js
  • /assets/css/vue-demo.css

Step 7: Add to WPMVC compilation cycle

You need to add the following entry in the scripts section of your package.json file in order for NPM and WPMVC to know that webpack is executable:

{
   ...,
  "scripts": {
    "webpack": "webpack --hide-modules"
  }
}

WPMVC will detect that the webpack.config.js file exists and will execute the script line defined above during its compilation cycle.


Step 8: Add Vue dependency and a watch

Step 7 will compile your Vue assets, but the browser will need Vue in order to run them, therefore you will need to include it to your project as an asset.

Paste the following code in your projects gulpfile.js file (after // START - CUSTOM TASKS line):

config.prescripts = ['vendor-js'];

/**
 * Vendor JS
 */
gulp.task('vendor-js', function() {
    return gulp.src([
            // Vue 2
            // './node_modules/vue/dist/vue.min.js',
            // Vue 3
            './node_modules/vue/dist/vue.global.prod.js',
        ])
        .pipe(gulp.dest('./assets/js'));
});

The task vendor-js will copy dependencies from NPM’s /node_modules folder into your project’s /assets for visibility. The config.prescripts = ['vendor-js'] line adds the task into WPMVC compilation process (before any JavaScript file in /assets/raw is processed).

Paste the following code in your projects gulpfile.js file (after the code above):

/**
 * Vue watch.
 */
gulp.task('watch-vue', async function () {
    gulp.watch([
        './assets/raw/vue/**/*.vue',
        './assets/raw/vue/components/**/*.vue',
        './assets/raw/vue/**/*.js',
    ], gulp.series('webpack'));
});

The task watch-vue adds a new watch command that will allow gulp to watch any changes in your Vue code and proceed to compile it automatically.

Run the following command at the root of your project to watch vue:

gulp watch-vue

Step 9: Run WPMVC compilation cycle

Run the following command at the root of your project:

gulp dev

The command above should run the WPMVC compilation process, including your added customizations to support Vue.

The following files should be created as output:

  • /assets/js/vue.min.js
  • /assets/js/vue-init.js
  • /assets/js/vue-demo.js
  • /assets/css/vue-demo.css

Note: gulp build and gulp deploy will also consider these customizations.


Step 10: Enqueue assets

Finally, you need to enqueue the assets into WordPress. You will use WPMVC auto-enqueue system for this.

Add the following to your /app/Config/app.php configuration file:

return [
    ...,
    'autoenqueue' => [
        'assets' => [
            /*
            vue 2
            [
                'id'        => 'vue',
                'asset'     => 'js/vue.min.js',
                'version'   => '2.6.14',
                'footer'    => true,
            ],
            */
            [
                'id'        => 'vue',
                'asset'     => 'js/vue.global.prod.js',
                'version'   => '3.2.47',
                'footer'    => true,
            ],
            [
                'id'        => 'vue-init',
                'asset'     => 'js/vue-init.js',
                'dep'       => ['vue'],
                'footer'    => true,
            ],
            [
                'id'        => 'vue-demo',
                'asset'     => 'js/vue-demo.js',
                'dep'       => ['vue-init'],
                'footer'    => true,
            ],
            [
                'id'        => 'vue-demo',
                'asset'     => 'css/vue-demo.css',
                'footer'    => 'all',
            ],
        ],

    ],
];

The configuration above will auto-enqueue all assets, you should be ready to view it in a browser.


UPDATED 2023: Troubleshooting

  1. If npm is indicating the gulp and gulp-wpmvc are missing, run npm install again.
  2. If you run into the error “missing fs/promises” then probably you will need to switch or download the latest version of npm. Make sure to delete the path /node_modules as well.
  3. You may require python 3 and python2. For python 2, you can download version 2.7 and rename python.exe into python2.exe.