브라우저 내 자바 스크립트에 노드 스타일이 필요합니까?


85

Node와 동일한 유연성 / 모듈성 / 사용 편의성을 제공하는 브라우저 내 자바 스크립트 용 라이브러리가 require있습니까?

더 자세한 정보를 제공하기 위해 : 그 이유 require는 다음과 같습니다.

  1. 다른 위치에서 코드를 동적으로로드 할 수 있습니다 (HTML에서 모든 코드를 연결하는 것보다 스타일이 더 좋습니다).
  2. 모듈 구축을위한 일관된 인터페이스를 제공합니다.
  3. 모듈이 다른 모듈에 의존하기 쉽습니다 (예를 들어 jQuery가 필요한 API를 작성할 수 있으므로 jQuery.ajax()
  4. 로드 된 자바 스크립트는 범위지정되어 있습니다 . 즉,로드 var dsp = require("dsp.js");할 수 있고 액세스 할 수 있습니다 dsp.FFT. 이는 내 로컬을 방해하지 않습니다.var FFT

이를 효과적으로 수행하는 도서관을 아직 찾지 못했습니다. 내가 사용하는 해결 방법은 다음과 같습니다.

  • coffeescript-concat- 다른 js를 요구하는 것은 쉽지만 컴파일해야합니다. 즉, 빠른 개발 (예 : 테스트 내 API 빌드)에는 적합하지 않습니다.

  • RequireJS- 인기 있고 간단하며 1-3을 해결하지만 범위 지정이 없다는 것은 실제 거래를 방해하는 요소 입니다 (나는 head.js 가 범위 지정이 없다는 점에서 비슷 하다고 생각 합니다.하지만 사용할 기회가 없었습니다. 마찬가지로 LABjs.wait()종속성 문제를 로드하고 수정 하지만 여전히 범위를 지정하지 않습니다.)

내가 알 수있는 한, 자바 스크립트의 동적 및 / 또는 비동기 로딩에 대한 많은 솔루션이있는 것처럼 보이지만 HTML에서 js를로드하는 것과 동일한 범위 지정 문제가있는 경향이 있습니다. 무엇보다도, 전역 네임 스페이스를 전혀 오염시키지 않지만 여전히 라이브러리를로드하고 사용할 수 있도록하는 자바 스크립트를로드하는 방법을 원합니다 (노드의 요구 사항과 마찬가지로).

2020 업데이트 : 모듈 은 이제 ES6의 표준이며 2020 년 중반부터 대부분의 브라우저에서 기본적으로 지원됩니다 . 모듈은 동기 및 비동기 (Promise 사용)로드를 모두 지원합니다. 나의 현재 권장 사항은 대부분의 새로운 프로젝트는 ES6 모듈을 사용하고 트랜스 파일러를 사용하여 레거시 브라우저 용 단일 JS 파일로 폴백하는 것입니다.

일반적으로 오늘날의 대역폭은 원래이 질문을 할 때보 다 일반적으로 훨씬 더 넓습니다. 따라서 실제로는 항상 ES6 모듈과 함께 트랜스 파일러를 사용하도록 합리적으로 선택하고 네트워크보다는 코드 효율성에 집중할 수 있습니다.

이전 편집 (또는 ES6 모듈이 마음에 들지 않는 경우) : 이 글을 작성한 후 RequireJS를 광범위하게 사용 했습니다 (이제 훨씬 더 명확한 문서가 있음). RequireJS는 제 생각에 정말 올바른 선택이었습니다. 저처럼 혼란스러워하는 사람들을 위해 시스템이 어떻게 작동하는지 명확히하고 싶습니다.

require일상적인 개발에 사용하실 수 있습니다 . 모듈은 함수 (일반적으로 개체 또는 함수)에서 반환하는 모든 것이 될 수 있으며 매개 변수로 범위가 지정됩니다. 다음을 사용하여 배포를 위해 프로젝트를 단일 파일로 컴파일 할 수도 있습니다 r.js(실제로는 require스크립트를 병렬로로드 할 수 있더라도 거의 항상 빠릅니다 ).

RequireJS와 node-style require like browserify (tjameson이 제안한 멋진 프로젝트) 사용의 주요 차이점은 모듈이 설계되고 요구되는 방식입니다.

  • RequireJS는 AMD (Async Module Definition)를 사용합니다. AMD에서는 require로드 할 모듈 (자바 스크립트 파일) 목록과 콜백 함수를받습니다. 각 모듈을로드하면 각 모듈을 콜백에 대한 매개 변수로 사용하여 콜백을 호출합니다. 따라서 진정한 비동기식이므로 웹에 적합합니다.
  • Node는 CommonJS를 사용합니다. CommonJS에서 require모듈을로드하고이를 객체로 반환하는 차단 호출입니다. 파일이 파일 시스템에서 읽히기 때문에 노드에서는 잘 작동합니다. 파일 시스템은 충분히 빠르지 만 파일을 동기식으로로드하는 데 훨씬 오래 걸릴 수 있기 때문에 웹에서는 제대로 작동하지 않습니다.

실제로 많은 개발자가 AMD를보기 전에 Node (및 CommonJS)를 사용했습니다. 또한 많은 라이브러리 / 모듈이 exportsAMD ( define함수 에서 모듈 반환)가 아닌 CommonJS ( 객체 에 항목 추가) 용으로 작성됩니다 . 따라서 많은 Node-turned 웹 개발자가 웹에서 CommonJS 라이브러리를 사용하기를 원합니다. <script>태그 에서로드하는 것이 차단 되기 때문에 가능합니다 . browserify와 같은 솔루션은 CommonJS (노드) 모듈을 가져 와서이를 래핑하여 스크립트 태그와 함께 포함 할 수 있습니다.

따라서 웹용 다중 파일 프로젝트를 개발하는 경우 RequireJS가 진정 웹용 모듈 시스템이기 때문에 강력하게 권장합니다 (공정한 공개에서 AMD는 CommonJS보다 훨씬 더 자연 스럽습니다). 최근에는 RequireJS를 사용하여 기본적으로 CommonJS 구문을 사용할 수 있으므로 구별이 덜 중요해졌습니다. 또한 RequireJS를 사용하여 Node에서 AMD 모듈을로드 할 수 있습니다 (나는 node-amd-loader를 선호하지만 ).


1
참고 RequireJS는 실제로 모듈성을 지원하고 범위를 지정할 수 있습니다. 물어 본 이후로 좀 더 광범위하게 사용했습니다. 제 생각에는 기능이 풍부하지만 효과적으로 사용하려면 많은 문서 읽기가 필요하며 완벽하기 전에 어떤 형태의 일류 동기식 로딩이 필요합니다.
Alex Churchill

1
비동기식이라는 구별이 그렇게 의미가 있습니까? 코드가 필요할 때마다 기본적으로 기능을 정의하기 때문에 계속할 수있는 것이 차단되어 있습니다.
Michael

답변:


17

엔더를 확인하십시오 . 많은 일을합니다.

또한 browserify 는 꽤 좋습니다. 나는 require-kiss ¹를 사용했고 작동합니다. 아마 다른 것들이있을 것입니다.

RequireJS에 대해 잘 모르겠습니다. 노드와 동일하지 않습니다. 다른 위치에서로드하는 데 문제가 발생할 수 있지만 작동 할 수 있습니다. 제공 메소드 또는 호출 할 수있는 것이있는 한.

TL; DR- 저는 browserify 또는 require-kiss를 권장합니다.


최신 정보:

1 : require-kiss 는 이제 죽었고 저자는 그것을 제거했습니다. 나는 그 이후로 문제없이 RequireJS를 사용하고 있습니다. require-kiss의 저자는 pakmanagerpakman을 작성 했습니다 . 전체 공개, 저는 개발자와 협력합니다.

개인적으로 RequireJS가 더 좋습니다. 디버그하기가 훨씬 쉽고 (개발 중에 별도의 파일을 가질 수 있고 프로덕션에 배포 된 단일 파일을 가질 수 있음) 견고한 "표준"을 기반으로 구축되었습니다.


require-kiss에 대한 링크가 죽은 것 같습니다. 간단한 (연구) 검색은 어디로도 이어지지 않았습니다. 어디로 갔습니까?
Joel Purra 2012-08-17

@JoelPurra-require-kiss가 제거되고 pakmanager로 대체되었습니다. 지금 require-js를 추천합니다. 답변을 업데이트했습니다.
beatgammit

여기에 좋은 대답 :), 내가 방금 한 질문이 이것과 비슷하지만 동시에 다른 질문을 확인하십시오. stackoverflow.com/questions/43237875/…
Webeng

16

여기서는 자바 스크립트 파일의 비동기 및 동기로드를 허용하는 작은 스크립트를 작성했습니다. 종속성이 없으며 Node.js 및 CommonJS와 호환됩니다. 설치는 매우 쉽습니다.

$ npm install --save @tarp/require

그런 다음 HTML에 다음 줄을 추가하여 메인 모듈을로드합니다.

<script src="/node_modules/@tarp/require/require.min.js"></script>
<script>Tarp.require({main: "./scripts/main"});</script>

메인 모듈 (및 모든 하위 모듈) 내 require()에서 CommonJS / NodeJS에서 알고있는대로 사용할 수 있습니다 . 전체 문서와 코드는 GitHub 에서 찾을 수 있습니다 .


main.js에있는 함수를 어떻게 사용합니까? 인스턴스 main.js를 들어 간단한을 가지고 myFunction합니다 alert("hello"). 전화 main.myFunction()할까요? 경고가되지 않습니까?
Brian Wiley

Tarp.require({ expose: true });작동 하려면 사용해야 합니까? 시험처럼?
Brian Wiley

10

코드를 구성하려는 초보자가있을 수 있음을 알고 있습니다. 이다 2020 , 당신은 모듈 JS 응용 프로그램을 고려하고 있다면, 당신은 시작한다 NPM웹팩 지금.

시작하기위한 몇 가지 간단한 단계는 다음과 같습니다.

  1. 프로젝트 루트에서 실행 npm init -y하여 npm 프로젝트를 초기화합니다.
  2. Webpack 모듈 번 들러를 다운로드합니다. npm install webpack webpack-cli
  3. index.html 파일을 만듭니다.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>App</title>
</head>
<body>

    <script src="_bundle.js"></script>
</body>
</html>

_bundle.js파일에 특별한주의를 기울 이십시오. 이것은 webpack에 의해 생성 된 최종 JS 파일이며 직접 수정하지 않습니다 (계속 읽으십시오).

  1. <project-root>/app.js다른 모듈을 가져올 파일을 만듭니다 .
const printHello = require('./print-hello');

printHello();
  1. 샘플 print-hello.js모듈을 만듭니다 .
module.exports = function() {
    console.log('Hello World!');
}
  1. 다음을 <project-root>/webpack.config.js만들고 복사하여 붙여 넣습니다.
var path = require('path');

module.exports = {
  entry: './app.js',
  output: {
    path: path.resolve(__dirname),
    filename: '_bundle.js'
  }
};

위의 코드에는 두 가지 점이 있습니다.

  • 항목 app.js은 JS 코드를 작성하는 곳입니다. 위에 표시된대로 다른 모듈을 가져옵니다.
  • 출력 _bundle.js은 webpack에서 생성 한 최종 번들입니다. 이것이 당신의 html이 마지막에 보게 될 것입니다.

-7. 열려있는 package.js및 교체 scripts다음 명령을 :

  "scripts": {
    "start": "webpack --mode production -w"
  },
  1. 마지막으로 스크립트 감시 를 실행하고 다음을 실행 app.js하여 _bundle.js파일을 생성합니다 npm start..
  2. 코딩을 즐기십시오!

1
2020 년에 이것은 정답으로 표시되어야합니다
p13rnd

9

Ilya Kharlamov 의 변형 , 크롬 개발자 도구와 잘 어울리는 코드가 있습니다.

//
///- REQUIRE FN
// equivalent to require from node.js
function require(url){
    if (url.toLowerCase().substr(-3)!=='.js') url+='.js'; // to allow loading without js suffix;
    if (!require.cache) require.cache=[]; //init cache
    var exports=require.cache[url]; //get from cache
    if (!exports) { //not cached
            try {
                exports={};
                var X=new XMLHttpRequest();
                X.open("GET", url, 0); // sync
                X.send();
                if (X.status && X.status !== 200)  throw new Error(X.statusText);
                var source = X.responseText;
                // fix (if saved form for Chrome Dev Tools)
                if (source.substr(0,10)==="(function("){ 
                    var moduleStart = source.indexOf('{');
                    var moduleEnd = source.lastIndexOf('})');
                    var CDTcomment = source.indexOf('//@ ');
                    if (CDTcomment>-1 && CDTcomment<moduleStart+6) moduleStart = source.indexOf('\n',CDTcomment);
                    source = source.slice(moduleStart+1,moduleEnd-1); 
                } 
                // fix, add comment to show source on Chrome Dev Tools
                source="//@ sourceURL="+window.location.origin+url+"\n" + source;
                //------
                var module = { id: url, uri: url, exports:exports }; //according to node.js modules 
                var anonFn = new Function("require", "exports", "module", source); //create a Fn with module code, and 3 params: require, exports & module
                anonFn(require, exports, module); // call the Fn, Execute the module
                require.cache[url]  = exports = module.exports; //cache obj exported by module
            } catch (err) {
                throw new Error("Error loading module "+url+": "+err);
            }
    }
    return exports; //require returns object exported by module
}
///- END REQUIRE FN

Lucio 감사합니다! 나는 오랫동안 이와 같은 최소한의 솔루션을 찾고있었습니다. 상대 경로를 지원하도록 확장했습니다. 아래를 참조하십시오.
Trausti Kristjansson 2014 년

5
(function () {
    // c is cache, the rest are the constants
    var c = {},s="status",t="Text",e="exports",E="Error",r="require",m="module",S=" ",w=window;
    w[r]=function R(url) {
        url+=/.js$/i.test(url) ? "" : ".js";// to allow loading without js suffix;
        var X=new XMLHttpRequest(),module = { id: url, uri: url }; //according to the modules 1.1 standard
        if (!c[url])
            try {
                X.open("GET", url, 0); // sync
                X.send();
                if (X[s] && X[s] != 200) 
                    throw X[s+t];
                Function(r, e, m, X['response'+t])(R, c[url]={}, module); // Execute the module
                module[e] && (c[url]=module[e]);
            } catch (x) {
                throw w[E](E+" in "+r+": Can't load "+m+S+url+":"+S+x);
            }
        return c[url];
    }
})();

차단 때문에 생산에 사용하지 않는 것이 좋습니다. (node.js에서 require ()는 블로킹 호출이 좋습니다).


"exports : {}"가 "module"의 속성이 아니어야합니까? 상기 통화 (R, module.exports 모듈) 일
루씨 M. TATO

@ LucioM.Tato 잘 모르겠습니다 . Modules 1.1 standard 에서 module.exports에 대한 언급을 볼 수 없습니다 . 당신은 항상 수출 얻기 위해 (module.id)가 필요 호출 할 수 있습니다
일리아 카를라 모프

예. 당신 말이 맞아요. node.js 모듈 구현을 생각하고있었습니다. Chrome Dev Tools와 잘 어울리도록 코드에 몇 가지 수정 사항을 추가했습니다 (디버그 시간 IDE로 사용하고 있습니다). 다른 사람에게 유용 할 경우를 대비하여이 질문에 대한 또 다른 답변으로 코드를 게시하겠습니다.
Lucio M. Tato


1

Require-stubrequire브라우저에서 노드 호환 을 제공 하고 모듈과 상대 경로를 모두 확인합니다. TKRequire (XMLHttpRequest)와 유사한 기술을 사용합니다. 결과 코드는 완전히 브라우저 require-stub화할 수 있으며 watchify.


0

다음은 상대 경로가있는 모듈의 재귀 적로드를 허용하는 Lucio M. Tato의 환상적인 답변에 대한 확장입니다.

다음은 솔루션을 수용 하는 github 프로젝트 와 사용 방법의 예입니다.

https://github.com/trausti/TKRequire.js

TKRequire.js를 사용하려면 헤더에 다음 줄을 포함하세요.

<script type = "text / javascript"src = "./ TKRequire.js"> </ script>

그런 다음 node.js에서와 같이 모듈을로드합니다.

var MyModule = require ( "./ relative / path / to / MyModule.js");


감사합니다 Trausti. 자바 스크립트를 사용하는 경우 github.com/luciotato/LiteScript (베타)를 확인해야합니다 . PD : 지금 어떤 레벨의 CC Saga를 플레이하고 있습니까? : P
Lucio M. Tato 2014-10-26

링크가 죽었습니다. 어떻게 코드를 잡고 살펴볼 수 있습니까?
PA.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.