Previous projects have been constructed using grunt, and then used requirejs to make modular. Requirejs official provides grunt plug-in for compression and merging. The current project has reached gulp, and it uses seajs in modularity, so naturally I also thought of the problem of module merging and compression.
Then when I first solved this problem, it was not very smooth. There was no particularly popular gulp plug-in for seajs merging and compression on npm. Although I also read a lot of issues on seajs github, most of them can only merge all module files into a total file. This is definitely no problem for single-page applications. However, for multi-page applications, it obviously violates the core of on-demand loading in modularity idea, so what I want is a method that can merge on-demand based on the modules that each page depends on.
The meaning of this on-demand merge is that on the one hand, it only merges the modules that a page depends on, and on the other hand, it can also filter out some modules that do not participate in the merge. The reason for considering this is that some modules, such as jquery, are all third-party dependent libraries, and may have a large file. The most important thing is that you will hardly change its code, so if these modules are not merged into the page's js, it will help to better utilize the browser cache. This article introduces a simple and feasible method to do seajs merge compression in small and medium-sized projects built on gulp.
Note: To illustrate the effect of seajs merge, this article provides a demonstration demo, which has two pages: login.html and regist.html, which are used to simulate two independent files in multi-page applications. You can view it through the following link:
http://liuyunzhuge.github.io/blog/seajs/dist/html/login.html
http://liuyunzhuge.github.io/blog/seajs/dist/html/regist.html
Taking login.html as an example, when viewing the source file of this page, you will see that in addition to referring to seajs and related configuration files common.js, it only references app/login as the main js of the page. This app/login module actually corresponds to js/app/login.js:
But in fact, this login.js relies on more modules js, and you can view the detailed js resources loaded by this page through chrome's source:
Before the login.js merge, its code looked like this:
However, in the first two screenshots, we did not see the three files: mod/mod1.js, mod/mod2.js, deps/fastclick.js. In addition to login.js, we also saw lib/bootstrap.js, lib/jquery.js, lib/jquery.validate.js. This is the effect of merging. On the one hand, the modules under the js/lib folder will not participate in the merger. On the other hand, the other hand, the other modules that the main js of the page depend on are merged into the main js file of the page.
The code related to this demo can be viewed through the following link:
https://github.com/liuyunzhuge/blog/tree/master/seajs
1. Merge ideas
In fact, the method is relatively simple, I will introduce it to it at the end.
1) Let me first talk about a folder structure that I organize the seajs module, which is like this:
This structure is borrowed from requirejs and try to flatten the file organization, which should not be too troublesome for small and medium-sized front-end projects. The functions of each folder are:
1) js/app stores the main js of each page, basically the logic of one page and one js
2) js/deps stores third-party modules that need to be merged into main js
3) js/lib stores third-party modules that do not need to participate in the merger
4) js/mod stores some js modules written by themselves in each project
5) common.js is the seajs configuration file.
2) In common.js, all the modules under js/lib are configured into the alias option, because these js do not participate in the merge and need to be used in the browser cache. Alias can facilitate us to update the loading addresses of these files when modifying or upgrading the files under js/lib:
Base is configured to the js folder. In module development, when I want to require other modules, my habit is to write module identifiers like mod/mod1 directly without relative identification. Even if the module to which the module to be defined exists in the same folder as it, this is also why I set the base directory to the js folder, which is a bit similar to the root directory of the site.
3) Merge idea: mainly utilize the two gulp plugins: gulp-seajs-transport and gulp-seajs-concat. Although they are not very popular on github, they have solved my problem well and are very simple to use:
(For more content, you need to check the source code link provided at the beginning of this article to find the relevant gulpfile.js file)
gulp-seajs-transport can help you turn seajs module files from anonymous modules to named modules. For example, js/mod/mod1.js looks like this before building:
But after transport processing, it will become:
This is a more critical point in seajs merge work. It is not like requirejs, just do concat directly; it must first be processed by a transport task, turn the anonymous module into a named module, and use the second parameter of define to describe all dependencies of this module, just like requirejs. Only after completing the transport can gulp-seajs-concat be used for merges. For reasons, please refer to: https://github.com/seajs/seajs/issues/426.
When gulp-seajs-concat is merged, it is very simple. Just tell it a base option. This base option is consistent with the base option in js/common.js. Because gulp-seajs-concat can find other module files it depends on based on the modules after base and transport.
4) This method should be used when using main js on the page:
The parameter name of use must be consistent with the main module ID of the merged main js. For example, after js/app/login.js merge, it looks like this:
The first define corresponding module is the main module in the merged file. The content of the red box is the id of the main module. When seajs use the module, the parameter name must be the same as this id. Otherwise, even if seajs successfully loads this file, it will not execute any code in the module. Because seajs has a rule: ID and path matching principle, which is somewhat related to this, that is: when seajs uses to contain multiple modules in a file, the main module in this file will be found according to the parameter name of the use. Only when they exactly match can they be found.
5) Compression obfuscation: Use gulp-uglify:
But to pay attention to the mangle, you must exclude the require exports module, otherwise it will cause some unexpected problems.
2. Summary of this article
Although the content of this article is very simple, it took a lot of time to solve the problem of this article when I first cut into gulp and seajs. Although the progress was much smoother than my situation at that time when I was preparing for the demo... No matter what, I hope the content of this article can help some friends more or less.