An example of using the RequireJS library in the ASP.NET MVC project

  • 2020-12-19 20:52:48
  • OfStack

RequireJS is a popular front-end modular development tool that is itself a library file for Javascript, known as ES3en.js.
The main functions of RequireJs:

(1) Realize the asynchronous loading of js files to avoid losing the response of web pages;

(2) Manage the dependencies between modules to facilitate code writing and maintenance.

Front-end modular development now has a number of tools, roughly divided into two categories, the first category is like dojo tall complete, dojo v1.8 after the built-in modular development components; The other category is tools like ES17en. js, sea. js that focus on modular development.

According to the rules of modular division, it can be divided into AMD and CMD. dojo and ES26en. js comply with the former, while ES28en. js comply with the CMD specification.

require works well in single-page applications, but for traditional multi-page applications, require is somewhat confusing and inconvenient.

This article explains how to apply require to the structure of ES37en.NET MVC and presents a compression script to achieve semi-automated compression.

Separate the js code
1 In general, one route of ES45en.NET MVC corresponds to one view, and 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

It is assumed here that _layout.cshtml is shared by all pages. 1 In general, we will refer to the common js libraries in _layout, such as jQuery, bootstrap, etc., so that other pages do not need to refer to these libraries again, which improves the efficiency of coding. However, different pages will eventually depend on different js, especially the custom js that implements the function of the page itself. As a result, we have to refer to the special js in other pages, or even write js directly in the page. For example, the following code often appears in View:


<script type="text/javascript">
 $(function(){...});
</script>

This can lead to a messy page, and the page < script > The code in the tag cannot be cached by the browser, increasing the length of the page code. The more important drawback is that libraries such as jQuery perform anonymous functions after loading onto the page, which takes a while, and if some pages don't need jQuery at all, as long as the page uses _layout as the layout page, then the initialization code for jQuery will inevitably execute, which is a waste. In fact, javascript's idea of modular loading is designed to solve these problems.

Next, let's plan our js with require and build js directories such as the structure below



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

Place the common library level js module directly in the js directory and the page level js in a subdirectory of app. Note that in app, there are 1 js files per page, which means that we need to extract the js for each page, which increases the structural complexity but avoids writing in the page < script > Bad labels. In addition, the common libraries in the js directory, in addition to the third party library, also includes the own libraries, as well as a file called config.js, which is a key file, which will be discussed later.

We can then delete all js references in _layout and use the @RenderSection command to request subpages to provide js references, _ES106en.cshtml:


<head>
...
@RenderSection("require_js_module", false)
...
</head>

The requirements for js are then relegated to each view page. According to require usage, we need to refer to ES115en.js in each child View and specify the main modules, which are the 1 js in the app directory above


@section require_js_module{
 <script src="@Url.Content("~/js/require.js")" data-main="@Url.Content("~/js/app/home.index.js")" ></script>
}

All of the js code will be written to js under app, which will standardize the js, make the page cleaner, and more importantly, the js can be compressed, cached and so on, further improve the performance efficiency

The public config
We know that in addition to using the require method, the main module often needs to use ES132en.config to configure the path of other modules, or 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 single-page applications, there is usually only one main module, so the above code is OK once written. However, in the case of multiple pages, there are multiple main modules, and each main module should contain such code, isn't it unscientific? So, you want to have one place where you can configure unified one, but how do you write it? We think of these configurations as one module, ES138en. js, and let the other main modules depend on this module. For example, config. js:

requirejs.config({
 paths: {
 "jquery": "/js/jquery.min",
 "bootstrap": "/js/bootstrap"
 },
 shim: {
 'bootstrap': {
  deps: ['jquery'],
  exports: "jQuery.fn.popover"
 }
 }
});

There is nothing special about the config. js, then just quote in ES146en. index. js


require(['../config','jquery', 'bootstrap'], function () {
 //main module code here

});

However, this is still wrong, because the modules that are dependent on the main module (config,jquery,bootstrap here), when loading, the loading order is uncertain, but they need the config module to load before the other modules. What to do? One compromise is to modify ES156en.index.js to the following code:


require(['../config'], function () {
 require(['home.index2']);
})
, define("home.index2", ['jquery', 'bootstrap'], function () {
 //main module code here
})

Using a named module ES162en.es163EN2 as the transition, require is manually loaded in the main module. This ensures that config is loaded before the main module executes, so that ES166en.index2 has loaded config at the time of loading.

The compression
require provide a compression tool, used to compress and merge js, for details, please visit http: / / requirejs org/docs/optimization html. Simply put, require provides a file called ES181en.js. The local node program (ES184en.js), executes the ES186en.js and passes in a few parameters to automatically analyze the dependencies between modules for the purpose of merging and compression. Again, this is easy for single-page applications, since there is only one main module, but what about multi-page applications? Fortunately, the compression tool supports 1 configuration file to guide compression, so 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" will find
  //nested dependencies.
  include: ["bootstrap", "config","jquery"]
 },
 //Now set up a build layer for each page, but exclude
 //the common one. "exclude" will exclude nested
 //the nested, built dependencies from "common". Any
 //"exclude" that includes built modules should be
 //listed before the build layer that wants to exclude it.
 //"include" the appropriate "app/main*" module since by default
 //it will not get added to the build since it is loaded by a nested
 //require in the page*.js files.
 {
 name:"app/home.index",
 exclude:["config"]
 },
 {
 name:"app/blog.create",
 exclude:["config"]
 },
 ...
 ]
}

Use this command to perform the compression, and the result of the compression will be saved to the js-ES194en directory:


<script type="text/javascript">
 $(function(){...});
</script>
0

The build.js script is actually an js object, and we added config to the common module and excluded it from the various main modules. In this way, all the common libraries including config will be compressed into one js, and the main module will not contain the extra config. As you can imagine, each page will download a maximum of two js at load time, and the code for the common modules will be "executed on demand."

To perform the above script compression, you need to have node installed. It can be downloaded here.

Automatic script
However, as the main module grows, you need to keep track of and modify the build file, which is also cumbersome. Therefore, based on ES213en. js, the author developed a script called ES215en-ES216en. js, which was used to automatically generate ES218en. js according to the directory structure:


<script type="text/javascript">
 $(function(){...});
</script>
1

The code here isn't complicated, but it's mostly about walking through the directory, generating the object, and finally serializing the object to ES223en.js. The reader can read and modify it for himself. Finally, write 1 bat to complete the 1-key compression function, ES226en. bat:


<script type="text/javascript">
 $(function(){...});
</script>
2

In this way, we simply implemented a convenient multi-page require scheme, and the final project directory might look 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



Related articles: