Search code examples
angularjswebpackoclazyload

Avoid code duplication in angular routing with oclazyload and webpack code splitting


I'm currently using angular 1.5 in a project and my routing looks like this:

const routes = ($stateProvider) => {

  $stateProvider
    .state('update', {
      url: '/update',
      template: '<update></update>',
      resolve: {
        lazyload: [ '$q', '$ocLazyLoad', function ($q, $ocLazyLoad) {
             console.log('start lazy');
             let deferred = $q.defer();
             require.ensure([], function () {
             let module = require('../components/update/update.module');
               let module = require('../components/update/update.module');
               $ocLazyLoad.load({
                 name: module.default.name
               });
               deferred.resolve(module);
             });
             return deferred.promise;
           }
         ]
      }
    })
    .state('login', {
      url: '/login',
      template: '<login></login>',
      resolve: {
        lazyload: [ '$q', '$ocLazyLoad', function ($q, $ocLazyLoad) {
            let deferred = $q.defer();
            require.ensure([], function () {
              let module = require('../components/login/login.module');
              $ocLazyLoad.load({
                name: module.default.name
              });
              deferred.resolve(module)
            });
            return deferred.promise;
          }
        ]
      }
    });

};

When I try to extract the duplicate code in a separate function like this:

function load (modulePath) {
    return function ($q, $ocLazyLoad) {
      let deferred = $q.defer();
      require.ensure([], function () {
      let module = require(modulePath);
        $ocLazyLoad.load({
          name: module.default.name
        });
        deferred.resolve(module);
      });
      return deferred.promise;
    }
  }

and use the load function in this manner:

$stateProvider
    .state('update', {
      url: '/update',
      template: '<update></update>',
      resolve: {
        lazyload: [ '$q', '$ocLazyLoad', load('../components/update/update.module')]
      }
    })

The routing doesn't work anymore and I get this error "Cannot find module "." at webpackMissingModule"


Solution

  • When using dynamic require, don't include the path and the extension in the argument.

    Put all your lazy module requires in a separate folder lazy.

    function load (state) {
      return function ($q, $ocLazyLoad) {
        let deferred = $q.defer();
        require.ensure([], function () {
          let module = require('../components/lazy/' +state+ '.module');
          $ocLazyLoad.load({
            name: module.default.name
          });
          deferred.resolve(module);
        });
        return deferred.promise;
      }
    }
    
    $stateProvider
    .state('update', {
      url: '/update',
      template: '<update></update>',
      resolve: {
        lazyload: [ '$q', '$ocLazyLoad', load('update')]
      }
    })

    You can use a different structure than the proposed one. Refer https://webpack.github.io/docs/context.html#dynamic-requires