Now, before we proceed to the code, I would like to emphasize on two important points which directly affect whether we’ll get a lazyLoad module or not:
In order for the module to become lazyLoad, one shouldn’t determine it as a dependency in relation to other modules.
The module cannot be imported anywhere except for the route for which you’d like to create this lazyLoad module.
Do not worry if that doesn’t sound clear just yet. In practice, you’ll quickly learn what’s what.
require.ensure() + $ocLazyLoad
require.ensure was introduced by the webpack team in the first of its versions. This method allows developers to dynamically create separate files (called “chunks” in webpack terms) containing certain pieces of the code which would further be loaded to the user in response to a certain action. And although the said method at its core isn’t the best one available for fulfilling this task, if you still prefer it, there’s nothing wrong about it. This method will perfectly suit those who want to create lazyLoad modules without spending too much on refactoring. Below, you can find an example of applying require.ensure for loading index.module.js:
For about.module.js the code will be identical, with the only difference that the paths to a module and some other parameters will be slightly different. Below, you can see an example of using require.ensure for loading about.module.js:
As you might have noticed all magic happens in this line:
$ocLazyLoad.load(module.HOME_ABOUT_MODULE);
There’s also one other way of defining the module which is by using an object:
$ocLazyLoad.load({ name: "home.module" });
The downside to this method, though, is that we restrict our freedom of actions. Suchwise, if we decide to rename the module in the future, we’ll have to make alterations in several fragments of the code. Also, you may make a typo when writing a new name of the module which is a very common problem. Well, if you ask me, I’d strongly recommend that you do not use this approach ever.
I would like you to pay attention to one very important nuance regarding about.module.js and further loading apps to the user. Take a look at the screenshot below:
Clicking the Home/About link, two files will be loaded simultaneously: index.module.chunk.js and about.module.chunk.js. This happens so because home.about URL is subsidiary of the home URL. You should keep this in mind. Running a little bit ahead, in the last section we will add one more module with a new URL and see that it will load only one file and nothing more.
System.import + $ocLazyLoad
I have long been thinking whether to write about this approach or not and then decide in favor of doing so. System.import is another construction derivative of the webpack command which despite being prohibited still remains one of the implementation options offered. Furthermore, this construction continues working in new webpack versions. What I suspect is that this is so because of the compatibility reasons. If you use this construction in your project, I’ve got bad news for you — it is currently in a deprecated status. OK, let’s move on.
Dynamic imports + $ocLazyLoad
Perhaps you’ve already heard that Chrome 63 and Safari Technology Preview 24 released a few updates and now developers can access dynamic imports. Yes, you’re right, those very dynamic imports that have been offered in the specification. Back in 2016, the webpack team has first applied dynamic imports support. In this section we will add one more module to the root of pages directory, to make sure lazyLoad works correctly. The structure for the branch import-es6 is given below:
If you use neither Babel nor TypeScript in your project then everything will work straight out of the box. But you know as well as I do that in the realities of the modern Front End it is very difficult to write a code using neither of the two tools. Let’s take a closer look at Babel. At first we need to install an additional plugin for babel which understands the syntax of dynamic imports: syntax-dynamic-import. If we don’t do this we will get an error:
Then we need to add .babelrc with the given settings:
Now, here’s the second unpleasant error which you may see below:
Yes, that’s right, ESLint doesn’t understand dynamic imports either. To correct this, what we need to do is install a special parser for ESLint babel-eslint and once we do this, all will work smoothly. Now let’s add .eslintrc with the settings:
The time has come for us to try out dynamic imports in business. Let’s test them using the new module:
As you may have noticed from the code, the webpack command has added a few pleasant perks to dynamic imports. Now we have an opportunity to specify both the name of the final chunk which will create webpack and the load method. To learn more about this option, click here to read. On the video below, we can see dynamic imports in work:
Component vs. Template
The property that we used for loading modules is component, however, if you prefer, you can use template instead. They work almost the same way with the only one difference: if you make a typo in the name of a component or the component will be unavailable for one reason or another, the console will contain an error and you may spend quite a while to find out what the problem is. If you use template, however, this error will not occur.
Useful Links
How to route to AngularJS 1.5 components
Lazy loading in UI-Router
Source code on GitHub
Project on Heroku
Instead of Conclusion
Using lazyLoad modules in the context of AngularJS apps is an excellent way to make your application less resource-intensive, more responsive and better distributed. Times change, requirements for applications grow and so does the amount of code which we deliver to the user. If earlier it was enough to assemble all code in one file, give it to the user and it was done and dusted now it’s become something of a luxury. There’s a tendency now to separate an application depending on the URL and allocate the common code.
That’s all for now. Thanks for your attention and special thanks to those who’ve read this article to the end.
P.S. If you’ve had a similar experience in realizing lazyLoad modules for AngularJS applications — share your comments below.
引言
当写一个单页面的时候,很多开发者会遇到这样的一个问题,如何懒加载模块,换句话说就是如何在用于点击某处,或者是要进入某个模块的时候,来加载这个模块相关的js,css,和html等。由于在现代前端开发的中,这将是一个巨大的JavaScript文件,所以,在这篇稳重中,我将会分享一些我自己的经验,展示一下在angularjs中如何实现懒加载模块,进而减少你的页面的初次加载时间。
为什么要在AngularJS 1.x版本实现懒加载
现在你可能会有一个疑惑,为什么要在angularjs的1.X版本区实现懒加载? 现在angular 5 都出来了。这个疑惑非常好。不过,你要知道有很多很多的项目依旧使用的是angularjs 1.x的版本,并且运行的还可能非常稳定。对于这样的项目来说。切换到新的版本不仅仅耗费人力也相当耗费财力。在市场上,angularjs1.x依旧有很高的需求。
Bicycles that already exist
在前端开发的世界里,对于一个同样的问题,有大量的工具和解决方案。每个人会选择一种最符合自己的需要、最符合自己已掌握的技术栈的一种方案。这不是一个坏事情,你应该接受这些现实并且继续接着开发下去。 有些人可能选择RequireJS,有些人可能选择curl.js,有些人可能选择Browserify,也有些人更偏爱XXX,XXX代表某种你更喜欢的工具。哈哈哈。不过在这篇文章中,我会给你展示如何使用Webpack, UI-Router, 和 ocLazyLoad去实现模块的懒加载,这些场景背后的逻辑都是在ocLazyLoad的帮助下实现的。如果我们想尝试着不用ocLazyLoad而仅仅使用require.ensure 来实现模块的懒加载,会出现类似下面的报错
项目结构
由于我不能给出我已经实现懒加载的项目的访问权限,所以我创建了一个精简版的小项目,我尽可能把这个小项目做的简单,因此你可以可以更清晰的看到模块和模块的关系。我也把这个小项目部署到了线上,你可以在这里观察这个项目的运行机制。再往下一点点呢,是这个项目的目录结构,展示的是git仓库里的require-ensure分支和system-import分支的目录结构。对于import-es6这个分支呢,我们还会持续的改进。
现在,在我们剖析代码之前,我想强调两点,这两点影响着我们是否可以把一个模块变成懒加载的模块
Now, before we proceed to the code, I would like to emphasize on two important points which directly affect whether we’ll get a lazyLoad module or not:
In order for the module to become lazyLoad, one shouldn’t determine it as a dependency in relation to other modules. The module cannot be imported anywhere except for the route for which you’d like to create this lazyLoad module. Do not worry if that doesn’t sound clear just yet. In practice, you’ll quickly learn what’s what.
require.ensure() + $ocLazyLoad require.ensure was introduced by the webpack team in the first of its versions. This method allows developers to dynamically create separate files (called “chunks” in webpack terms) containing certain pieces of the code which would further be loaded to the user in response to a certain action. And although the said method at its core isn’t the best one available for fulfilling this task, if you still prefer it, there’s nothing wrong about it. This method will perfectly suit those who want to create lazyLoad modules without spending too much on refactoring. Below, you can find an example of applying require.ensure for loading index.module.js:
For about.module.js the code will be identical, with the only difference that the paths to a module and some other parameters will be slightly different. Below, you can see an example of using require.ensure for loading about.module.js:
As you might have noticed all magic happens in this line: $ocLazyLoad.load(module.HOME_ABOUT_MODULE);
There’s also one other way of defining the module which is by using an object: $ocLazyLoad.load({ name: "home.module" });
The downside to this method, though, is that we restrict our freedom of actions. Suchwise, if we decide to rename the module in the future, we’ll have to make alterations in several fragments of the code. Also, you may make a typo when writing a new name of the module which is a very common problem. Well, if you ask me, I’d strongly recommend that you do not use this approach ever.
I would like you to pay attention to one very important nuance regarding about.module.js and further loading apps to the user. Take a look at the screenshot below:
Clicking the Home/About link, two files will be loaded simultaneously: index.module.chunk.js and about.module.chunk.js. This happens so because home.about URL is subsidiary of the home URL. You should keep this in mind. Running a little bit ahead, in the last section we will add one more module with a new URL and see that it will load only one file and nothing more.
System.import + $ocLazyLoad I have long been thinking whether to write about this approach or not and then decide in favor of doing so. System.import is another construction derivative of the webpack command which despite being prohibited still remains one of the implementation options offered. Furthermore, this construction continues working in new webpack versions. What I suspect is that this is so because of the compatibility reasons. If you use this construction in your project, I’ve got bad news for you — it is currently in a deprecated status. OK, let’s move on.
Dynamic imports + $ocLazyLoad Perhaps you’ve already heard that Chrome 63 and Safari Technology Preview 24 released a few updates and now developers can access dynamic imports. Yes, you’re right, those very dynamic imports that have been offered in the specification. Back in 2016, the webpack team has first applied dynamic imports support. In this section we will add one more module to the root of pages directory, to make sure lazyLoad works correctly. The structure for the branch import-es6 is given below:
If you use neither Babel nor TypeScript in your project then everything will work straight out of the box. But you know as well as I do that in the realities of the modern Front End it is very difficult to write a code using neither of the two tools. Let’s take a closer look at Babel. At first we need to install an additional plugin for babel which understands the syntax of dynamic imports: syntax-dynamic-import. If we don’t do this we will get an error:
Then we need to add .babelrc with the given settings:
Now, here’s the second unpleasant error which you may see below:
Yes, that’s right, ESLint doesn’t understand dynamic imports either. To correct this, what we need to do is install a special parser for ESLint babel-eslint and once we do this, all will work smoothly. Now let’s add .eslintrc with the settings:
The time has come for us to try out dynamic imports in business. Let’s test them using the new module:
As you may have noticed from the code, the webpack command has added a few pleasant perks to dynamic imports. Now we have an opportunity to specify both the name of the final chunk which will create webpack and the load method. To learn more about this option, click here to read. On the video below, we can see dynamic imports in work:
Component vs. Template The property that we used for loading modules is component, however, if you prefer, you can use template instead. They work almost the same way with the only one difference: if you make a typo in the name of a component or the component will be unavailable for one reason or another, the console will contain an error and you may spend quite a while to find out what the problem is. If you use template, however, this error will not occur.
Useful Links How to route to AngularJS 1.5 components Lazy loading in UI-Router Source code on GitHub Project on Heroku Instead of Conclusion Using lazyLoad modules in the context of AngularJS apps is an excellent way to make your application less resource-intensive, more responsive and better distributed. Times change, requirements for applications grow and so does the amount of code which we deliver to the user. If earlier it was enough to assemble all code in one file, give it to the user and it was done and dusted now it’s become something of a luxury. There’s a tendency now to separate an application depending on the URL and allocate the common code.
That’s all for now. Thanks for your attention and special thanks to those who’ve read this article to the end.
P.S. If you’ve had a similar experience in realizing lazyLoad modules for AngularJS applications — share your comments below.
https://medium.com/@var_bin/angularjs-webpack-lazyload-bb7977f390dd