[Vuejs]-How to create a modular client-side / serverside application with different codebases (the JS part)?

0πŸ‘

You can use Webpack with Code splitting

There are three general approaches to code splitting available:

  • Entry Points: Manually split code using entry configuration.
  • Prevent Duplication: Use the SplitChunksPlugin to dedupe and split chunks.
  • Dynamic Imports: Split code via inline function calls within modules.

Assuming that the high level modules (cms.js, newsletter.js, …) are independent from each other, and only depends on generic.js

Folder strcuture

src/
β”œβ”€β”€ cms/
β”‚   β”œβ”€β”€ index.ts
β”‚   β”œβ”€β”€ ...
β”œβ”€β”€ newsletter/
β”‚   β”œβ”€β”€ index.ts
β”‚   β”œβ”€β”€ ...
└── generics/
    β”œβ”€β”€ index.ts
    β”œβ”€β”€ messages.ts
    β”œβ”€β”€ dialogs.ts

src/generics/dialogs.ts

export function open(title: string) {
    console.log('Opening dialog : ', title);
}

src/generics/messages.ts

export function alert(msg: string) {
    console.log('alert : ', msg);
}

src/generics/index.ts

import * as m from './messages';
import * as d from './dialogs';

export let messages = m ;
export let dialogs = d;

src/cms/index.ts

import { dialogs, messages } from '../generics';

messages.alert('CMS started ...');

src/newsletter/index.ts

import { dialogs, messages } from '../generics';

messages.alert('Newsletter started ...');

Webpack Code splitting

1. Entry Points

This is by far the easiest, and most intuitive, way to split code.
However, it is more manual and has some pitfalls.

So in your config file, you will have to manually declare your modules using the entry object :

// webpack.config.js
const path = require('path');

module.exports = {
    mode: 'development',
    entry: {
        'newsletter': './src/newsletter/index.ts',
        'cms': './src/cms/index.ts',
    },
    module: {
        rules: [
        {
            test: /\.ts?$/,
            use: 'ts-loader',
            exclude: /node_modules/
        }
        ]
    },
    resolve: {
        extensions: [ '.ts', '.js' ]
    },
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist'),
        publicPath: "dist/",
    }
};

With this config, you will have two modules in the dist folder :

               Asset      Size      Chunks             Chunk Names
       cms.bundle.js   4.6 KiB         cms  [emitted]  cms
newsletter.bundle.js  4.64 KiB  newsletter  [emitted]  newsletter

Because the cms and newsletter modules depends on the generics module, this module is bundled (copied) with them.

2. Prevent Duplication with SplitChunksPlugin

Add the optimization.splitChunks config to the webpack.config.js file :

optimization: {
    splitChunks: {
        chunks: 'all',
        minChunks: 1,
        name: 'generics',
        minSize: 10,
    }
}

Now the generics module is in it’s own chunk (remember to include it in your HTML file), and the build will generate 3 files :

               Asset      Size      Chunks             Chunk Names
       cms.bundle.js  5.85 KiB         cms  [emitted]  cms
  generics.bundle.js  1.61 KiB    generics  [emitted]  generics
newsletter.bundle.js   5.9 KiB  newsletter  [emitted]  newsletter 

3. Dynamic Imports

Change src/cms/index.ts to use dynamic imports :

import(/* webpackChunkName: "generics" */ '../generics').then(generics => {
    console.log('Generics module loaded ...');
    generics.messages.alert('CMS started ...');
});

Change src/newsletter/index.ts to use dynamic imports :

import(/* webpackChunkName: "generics" */ '../generics').then(generics => {
    console.log('Generics module loaded ...');
    generics.messages.alert('Newsletter started ...');
});

You will also have to change some Typescript compile options (and maybe install a polyfill for Promise) :

"module": "esnext",
"lib": [
    "es2015"
]   

Now you don’t have to include the generics module in your HTML file. When the import() is executed, Webpack will fetch the generics module from the server and cache it.

Hope this will help you get started πŸ™‚

Edit (response to comment) :

If the modules are in separate projects. You will use npm or yarn to manage dependencies.
For example, in the newsletter project’s package.json, you will add
generics as a dependency.

Now, you have to use non-relative paths for your import. So for example, the dynamic import code will be :

import(/* webpackChunkName: "generics" */ 'generics').then(generics => {
    console.log('Generics module loaded ...');
    generics.messages.alert('Newsletter started ...');
});

If you want to bundle all your code, you could add a main module. This module will have dependencies to all the other modules. Then in the index.ts of this modules, import all the other modules. This index.ts should be the entry point in Webpack config.

Keep in mind, that bundling all you code base in a single file is not recomended most of the time for large single page applications, because it can easily get to >8Mb. Webpack default performance recommendation is ~250kB per file.

Leave a comment