Requirejs is a popular tool for front-end modular development, itself a JavaScript library file, i.e. Require.js.
Main functions of Requirejs:
(1) To realize the asynchronous loading of JS files to avoid web page loss of response;
(2) Management of the dependencies between modules, easy to write code and maintenance.
Front-End modular development There are now a number of tools, broadly divided into two categories, such as dojo, such as tall, dojo v1.8 has built a modular development component, the other is like require.js,sea.js this focus on the modular development tool.
From the modular division of the rules to differentiate, mainly divided into AMD, cmd two categories, Dojo, Require.js compliance with the former, and sea.js follow the CMD specification.
Require in a single page application can be a duck, however for the traditional multiple-page application, the use of require is somewhat confusing and inconvenient.
This article explains how to apply require in the structure of asp.net mvc, and gives a compression script to achieve semi-automatic compression.
Separating the JS code
in general asp.net an MVC route corresponds to a view, the file structure of the view may be as follows:
Views
|--shared
|--_layout.cshtml
|--home
|--index.cshtml
|--blog
|--create.cshtml
|--edit.cshtml
|--detail.cshtml
|--index.cshtml
This assumes that _layout.cshtml is shared by all pages. In general, we will refer to the Public JS class library in _layout, such as jquery,bootstrap, etc., so that other pages do not need to refer to these class libraries again, improve the efficiency of coding. However, different pages will eventually depend on different JS, especially the function of the page itself to customize the JS, so we have to refer to the other pages of the special JS, and even the JS directly written in the page, such as the following code will often appear in the view:
<script type= "Text/javascript" >
$ (function () {...});
</script>
This can cause the page to be more cluttered, and the page <script> tag code cannot be cached by the browser, increasing the length of the page code. The more important flaw is that class libraries such as jquery execute anonymous functions after they are loaded into the page, which takes some time, and if some pages don't need jquery at all, as long as the page takes _layout as a layout page, then jquery's initialization code will inevitably execute, This is a waste. In fact, JavaScript's modular loading idea is designed to solve these problems.
Next we'll use require to plan our JS, and build a JS directory like the following structure
JS
|--app
|--home.index.js
|--blog.create.js
|--blog.edit.js
|--blog.detail.js
| Blog.index.js
|--jquery.js
|--bootstrap.js
|--underscore.js
|--jquery.ui.js
| Jquery.customplugin.js
|--config.js
|--require.js
The common class Library level JS module directly placed in the JS directory, and the page level of JS placed in a subdirectory of the app record. Note that in app, each page is a JS file, which means we need to extract the page's respective JS, although this increases the complexity of the structure, but avoids the bad habits of the page with handwriting <script> labels. In addition, in the JS directory of the Public library, in addition to the third party's library, also includes its own development of the library, there is a file called Config.js, this document is very important, will be said later.
We can then delete all the JS references in the _layout and use the @rendersection command to require the subpage to provide the JS reference, _layout.cshtml:
So the demand for JS is decentralized to each view page, according to require usage, we need to refer to the require.js in each child view, and specify the main module, and these main modules are above the app directory of JS
@section require_js_module{
<script src= "@Url. Content (" ~/js/require.js ")" data-main= "@Url. Content (" ~/js/ App/home.index.js ")" ></script>
}
All JS code will be written to the app under JS, so that the specification of JS, make the page cleaner, more importantly, these JS can also be compressed, as well as browser caching, and further improve the efficiency of implementation
Public Config
we know that in addition to using the Require method, the main module often needs to configure the paths of other modules through require.config, and even shim, for example, the following code often appears at the beginning of the main module:
Require.config ({
paths: {
"jquery": "Lib/jquery.min",
"underscore": "Lib/underscore.min",
" Backbone ":" Lib/backbone.min "
},
shim: {
' underscore ': {
exports: ' _ '
},
' backbone ': {
Deps: [' underscore ', ' jquery '],
exports: ' Backbone '}}}
);
For a single page application, the main module is often only one, so the above code to write over the OK. However, in the case of multiple pages, the main module has more than one, each of the main modules to contain such code, it is not very scientific? So, want to have a unified configuration place, but how should write it? We think of these configurations as a modular config.js, so that other main modules can rely on this module, such as the following config.js:
Requirejs.config ({
paths: {
"jquery": "/js/jquery.min",
"bootstrap": "/js/bootstrap"
},
Shim: {
' bootstrap ': {
deps: [' jquery '],
exports: "JQuery.fn.popover"}}
);
Config.js's writing is nothing special, and then just refer to the Home.index.js
Require (['.. /config ', ' jquery ', ' bootstrap '], function () {
//main module code here
});
But this is not true, because the main module depends on the module (here Config,jquery,bootstrap), loading, loading sequence is uncertain, but also need config module in other modules before loading, how to do? A compromise solution is to modify the Home.index.js to become the following code:
Require (['.. /config '], function () {
require ([' home.index2 '])
, define ("Home.index2", [' jquery ', ' Bootstrap '], function () {
//main module code here
})
Using a named module HOME.INDEX2 as a transition, manually require in the main module, which ensures that config is loaded before the main module is executed, so that Home.index2 has loaded config when it loads.
Compression
require provides a compression tool for compressing and merging JS, please move to http://requirejs.org/docs/optimization.html for details. Simply put, require provides a file called R.js, which, through the local Node program (Node.js), executes the r.js and passes in some parameters to automatically analyze the dependencies between the modules to achieve the purpose of merging and compressing. Again, this is easy for a single page application because there is only one main module, but what about multiple pages? Fortunately, this compression tool supports the use of a configuration file to guide compression, so that we can write the following configuration script build.js:
var build = {appdir: '. /js ', BaseURL: '. ', dir: '. /js-built ', Mainconfigfile: '.
/js/config.js ', modules: [//first set up the common build layer. {//module names are relative to BaseURL name: ' config ',//list common-dependencies here.
Only need to list//top level dependencies, "include" 'll find//nested dependencies. Include: ["Bootstrap", "config", "jquery"]},//now set up a builds layer for each page, but exclude//the common one. "Exclude" would exclude nested//the nested, built dependencies from "common".
Any//"exclude" that includes built modules should is//listed before the build layer that wants to exclude it. "include" appropriate "app/main*" module since by default//it'll not get added to the build since it is loaded B
Y a nested//require in the page*.js files.
{name: ' App/home.index ', exclude:[' config '}, {name: ' app/blog.create ', exclude:[' config '}, ...] }
This command is used to perform the compression, and the results of the compression are saved to the Js-build directory:
Build.js script is actually a JS object, we add config to the public module, and in each main module to exclude it. In this way, all public libraries including config will be compressed into a JS, and the main module will not contain redundant config. As you can imagine, each page in the load will only download two JS, and the public module code will be "on-demand execution."
To perform the above script compression, you need to have node installed. Can be downloaded from here.
Automatic scripting
However, as the main module increases, it is also cumbersome to track and modify the build file at any time. Then, based on Node.js, I developed a script called Build-build.js, which is used to automatically generate Build.js according to the directory structure:
FS = require (' FS ');
var target_build = process.argv[2];
Console.log (__filename);
var pwd = __dirname;
var Js_path = pwd.substring (0,pwd.lastindexof (' \ \)) + ' \\js ';
Console.log (' JS path: ' + Js_path);
var App_path = Js_path + ' \\app ';
Console.log (' JS app path: ' +app_path ');
var app_modules = [];
var global_modules = []; Build JSON object var build = {appdir: '.. /js ', BaseURL: '. ', dir: '.
/js-built ', modules: [//first set up the common build layer. {//module names are relative to BaseURL name: ' config ',//list common-dependencies here.
Only need to list//top level dependencies, "include" 'll find//nested dependencies.
Include: []}]} fs.readdir (App_path,function (err,files) {//body ... if (err) throw err;
for (var i in files) {//put module in app_modules var dotindex = Files[i].lastindexof ('. ');
if (dotindex >= 0) {var extension = files[i].substring (dotindex+1,files[i].length); if (Extension = = ' js ') {App_modules.push ({name: ' app/') + files[i].substring (0,dotindex), exclude: [' config ']});
to (Var j in App_modules) {Build.modules.push (app_modules[j]);
} fs.readdir (Js_path,function (err,files) {if (err) throw err;
for (var i in files) {//put module in app_modules var dotindex = Files[i].lastindexof ('. ');
if (dotindex >= 0) {var extension = files[i].substring (dotindex+1,files[i].length);
if (Extension = = ' js ') {Global_modules.push (files[i].substring (0,dotindex));
}} build.modules[0].include = Global_modules;
Console.log (build);
var t = pwd + ' \ \ ' + target_build;
Console.log (t);
var fd = Fs.opensync (t, ' w ');
Fs.closesync (FD);
var json = json.stringify (build);
Fs.writefilesync (t, JSON);
});
});
The code here is not complex, mainly to traverse the directory, generate objects, and finally serialize objects into build.js. Readers can read and modify them themselves. Finally, write a bat, complete a key compression function, BUILD.bat:
@echo off
set pwd=%~p0
set pwd=%pwd:\=/%
cd "D:\node"
node.exe%pwd%build-build.js
build.js Node.exe%pwd%r.js-o%pwd%build.js
cd%~dp0
In this way, we simply implemented a convenient multiple-page require solution, the last project directory may be like this:
Views
|--shared
|--_layout.cshtml
|--home
|--index.cshtml
|--blog
| create.cshtml
|--edit.cshtml
|--detail.cshtml
|--index.cshtml
build
|--build.js
|--r.js
|--build-build.js
|--build.bat
js
|--app
|--home.index.js
| Blog.create.js
|--blog.edit.js
|--blog.detail.js
|--blog.index.js
|--jquery.js
| Bootstrap.js
|--underscore.js
|--jquery.ui.js
|--jquery.customplugin.js
|--config.js
|--require.js