>  기사  >  웹 프론트엔드  >  ASP.NET MVC 프로젝트에서 RequireJS 라이브러리를 사용하는 사용 예_javascript 팁

ASP.NET MVC 프로젝트에서 RequireJS 라이브러리를 사용하는 사용 예_javascript 팁

WBOY
WBOY원래의
2016-05-16 15:15:331883검색

RequireJS는 프론트엔드 모듈 개발에 널리 사용되는 도구로, require.js라는 Javascript 라이브러리 파일입니다.
RequireJ의 주요 기능:

(1) 웹페이지의 응답 손실을 방지하기 위해 js 파일의 비동기 로딩을 구현합니다.

(2) 모듈 간의 종속성을 관리하여 코드 작성 및 유지 관리를 용이하게 합니다.

프론트엔드 모듈식 개발을 위한 많은 도구가 있으며 일반적으로 두 가지 범주로 나뉩니다. 하나는 dojo v1.8 이후에 내장된 모듈식 개발 구성 요소가 있는 dojo와 같은 고급 도구입니다. .js가 필요하며, sea.js는 모듈 개발에 초점을 맞춘 도구입니다.

모듈 분할 규칙에 따르면 크게 AMD와 CMD 두 가지로 구분됩니다. Dojo와 require.js는 전자를 따르고, sea.js는 CMD 사양을 따릅니다.

require는 단일 페이지 애플리케이션에서 잘 작동하지만 기존의 다중 페이지 애플리케이션에서는 require를 사용하는 것이 다소 혼란스럽고 불편할 수 있습니다.

이 글에서는 ASP.NET MVC 구조에 require를 적용하는 방법을 설명하고, 반자동 압축을 달성하기 위한 압축 스크립트를 제공합니다.

JS 코드 분리
일반적으로 ASP.NET MVC의 경로는 뷰에 해당합니다.


Views
 |--Shared
 |--_layout.cshtml
 |--Home
 |--Index.cshtml
 |--Blog
 |--Create.cshtml
 |--Edit.cshtml
 |--Detail.cshtml
 |--Index.cshtml

_layout.cshtml은 모든 페이지에서 공유된다고 가정합니다. 일반적인 상황에서는 _layout에서 jQuery, 부트스트랩 등과 같은 공개 js 라이브러리를 참조하므로 다른 페이지에서 이러한 라이브러리를 다시 참조할 필요가 없으므로 코딩 효율성이 향상됩니다. 그러나 서로 다른 페이지는 결국 서로 다른 js, 특히 페이지 자체의 기능을 구현하는 사용자 정의 js에 의존하게 됩니다. 이러한 방식으로 우리는 다른 페이지에서 특수 js를 참조하거나 다음과 같이 페이지에 직접 js를 작성해야 합니다. 코드는 보기에 자주 나타납니다:

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

이로 인해 페이지가 혼란스러워지고 페이지의 3f1c4e4b6b16bbbd69b2ee476dc4f83a 태그에 있는 코드가 브라우저에서 캐시될 수 없게 되어 페이지 코드 길이가 늘어납니다. 더 중요한 결함은 jQuery와 같은 라이브러리가 페이지에 로드된 후 익명 함수를 실행한다는 점입니다. 이 작업에는 시간이 좀 걸립니다. 일부 페이지에 jQuery가 전혀 필요하지 않은 경우 페이지에서 _layout을 레이아웃 페이지로 사용하는 한 jQuery는 초기화 코드가 필연적으로 실행되므로 낭비입니다. 사실 자바스크립트의 모듈러 로딩 아이디어는 이러한 문제를 해결하기 위한 것입니다.

다음으로 require를 사용하여 js를 계획하고 다음 구조로 js 디렉토리를 구축합니다


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

공용 라이브러리 수준 js 모듈을 js 디렉터리에 직접 배치하고 페이지 수준 js를 앱의 하위 디렉터리에 배치합니다. 앱의 각 페이지에는 js 파일이 있으므로 각 페이지의 js를 추출해야 합니다. 이로 인해 구조적 복잡성이 증가하지만 페이지에 3f1c4e4b6b16bbbd69b2ee476dc4f83a 태그를 작성하는 나쁜 습관을 피할 수 있습니다. 또한, js 디렉터리의 공용 라이브러리에는 타사 라이브러리 외에도 자체 개발한 라이브러리와 config.js라는 파일이 포함되어 있습니다. 이 파일은 매우 중요하므로 나중에 설명하겠습니다.

그런 다음 _layout에서 모든 js 참조를 삭제하고 @RenderSection 명령을 사용하여 하위 페이지가 js 참조 _layout.cshtml을 제공하도록 요구할 수 있습니다.

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

이렇게 하면 js에 대한 수요가 각 뷰 페이지로 분산됩니다. require의 사용법에 따라 각 하위 뷰에서 require.js를 참조하고 기본 모듈을 지정해야 하며 이러한 기본 모듈은 각 js 위의 app 디렉토리

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

모든 js 코드는 js를 표준화하고 페이지를 더 깔끔하게 만드는 앱 아래에 작성됩니다. 더 중요한 것은 이러한 js를 브라우저에서 압축하고 캐시하여 실행 효율성을 더욱 향상시킬 수도 있다는 것입니다.

공개 구성
메인 모듈은 require 메소드를 사용하는 것 외에도 require.config를 통해 다른 모듈의 경로를 구성해야 하는 경우가 많으며 심지어 shim도 필요하다는 것을 알고 있습니다. 예를 들어, 메인 모듈의 시작 부분에 다음 코드가 자주 나타납니다. 모듈:

require.config({
 paths: {
 "jquery": "lib/jquery.min",
 "underscore": "lib/underscore.min",
 "backbone": "lib/backbone.min"
 },
 shim: {
 'underscore':{
  exports: '_'
 },
 'backbone': {
  deps: ['underscore', 'jquery'],
  exports: 'Backbone'
 }
 }
});

단일 페이지 애플리케이션의 경우 메인 모듈이 하나만 있는 경우가 많기 때문에 위 코드를 한 번만 작성해도 괜찮습니다. 그런데 여러 페이지의 경우에는 메인 모듈이 여러 개 있고, 각 메인 모듈마다 이런 코드가 들어가야 하는 것은 비과학적인 것 아닌가요? 그럼 통일된 설정 장소가 있으면 좋겠는데 어떻게 작성해야 할까요? 우리는 이러한 구성을 config.js 모듈로 사용하고 다음 config.js와 같이 다른 주요 모듈이 이 모듈에 종속되도록 할 수 있다고 생각했습니다.
requirejs.config({
 paths: {
 "jquery": "/js/jquery.min",
 "bootstrap": "/js/bootstrap"
 },
 shim: {
 'bootstrap': {
  deps: ['jquery'],
  exports: "jQuery.fn.popover"
 }
 }
});

config.js를 작성하는 방식에는 특별한 것이 없습니다. 다음으로 home.index.js에서

만 인용하면 됩니다.
require(['../config','jquery', 'bootstrap'], function () {
 //main module code here

});

그러나 이렇게 작성하는 것은 여전히 ​​잘못된 것입니다. 왜냐하면 메인 모듈이 의존하는 모듈(여기서는 config, jquery, bootstrap)이 로드될 때 로딩 순서가 불확실하지만 그 전에 config 모듈을 로드해야 하기 때문입니다. 다른 모듈, 어떻게 해야 할까요? 타협 해결책은 home.index.js를 다음 코드로 수정하는 것입니다.

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

使用一个命名的模块home.index2作为过渡,在主模块中手动require,这样可以保证config在主模块执行之前加载,也就使得home.index2在加载的时候已经加载了config了。

压缩
require提供一个压缩工具,用于压缩和合并js,详情请移步至http://requirejs.org/docs/optimization.html。简单的说,require提供一个叫r.js的文件,通过本地的node程序(Node.js),执行这个r.js并传入一些参数,即可自动分析模块互相之间的依赖,以达到合并和压缩的目的。同样的,这对于单页面应用来说是容易的,因为主模块只有一个,但是对于多页面又如何做呢?好在这个压缩工具支持用一个配置文件来指导压缩,这样的话,我们可以编写下面的配置脚本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"]
 },
 ...
 ]
}

通过这个命令来执行压缩,压缩的结果将被保存到js-build目录:

node.exe r.js -o build.js

build.js脚本实际上是一个js对象,我们将config加入公共模块,而在各个主模块中将其排除。这样,所有的公共库包括config将压缩成一个js,而主模块又不会包含多余的config。这样可想而知,每个页面在加载时最多只会下载两个js,而且公共模块的代码会“按需执行”。

执行上面的脚本压缩,需要安装有node。可以在从这里下载。

自动脚本
但是,随着主模块的增加,需要随时跟踪和修改这个build文件,这也是很麻烦的。于是,笔者基于node.js开发了一个叫build-build.js的脚本,用来根据目录结构自动生成build.js:

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" will 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']
  });
  }
 }
 }

 for(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);
 });
});

这里的代码并不复杂,主要是遍历目录,生成对象,最后将对象序列化为build.js。读者可以自行阅读并修改。最后,编写一个bat,完成一键压缩功能,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

这样,我们就简单实现了一个方便的多页面require方案,最后项目目录可能是这样的:

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


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.