ExpressJS 응용 프로그램을 구성하는 방법?


527

NodeJS에 ExpressJS 웹 프레임 워크를 사용하고 있습니다.

ExpressJS를 사용하는 사람들은 환경 (개발, 생산, 테스트 ...), 경로 등을에 배치합니다 app.js. 큰 응용 프로그램이있을 때 app.js가 너무 커서 아름다운 방법이 아니라고 생각합니다!

이 디렉토리 구조를 갖고 싶습니다.

| my-application
| -- app.js
| -- config/
     | -- environment.js
     | -- routes.js

내 코드는 다음과 같습니다.

app.js

var express = require('express');
var app = module.exports = express.createServer();

require('./config/environment.js')(app, express);
require('./config/routes.js')(app);

app.listen(3000);

config / environment.js

module.exports = function(app, express){
    app.configure(function() {
    app.use(express.logger());
    });

    app.configure('development', function() {
    app.use(express.errorHandler({
        dumpExceptions: true,
        showStack: true
    }));
    });

    app.configure('production', function() {
    app.use(express.errorHandler());
    });
};

config / routes.js

module.exports = function(app) {
    app.get('/', function(req, res) {
    res.send('Hello world !');
    });
};

내 코드는 잘 작동하며 디렉토리의 구조가 아름답다고 생각합니다. 그러나 코드를 수정해야했고 코드가 훌륭하고 아름답다는 것을 확신하지 못합니다.

내 디렉토리 구조를 사용하고 코드를 조정하거나 하나의 파일 (app.js)을 사용하는 것이 더 낫습니까?

당신의 조언에 감사드립니다!


이런 식으로 수행하는 성능 문제가 여전히 숨어 있습니까? 나는 어딘가 (익스프레스 그룹)를 읽는 것을 기억합니다. 이와 같은 모든 것을 분리하면 엄청난 성능을 잃습니다. reqs / sec와 같은 것은 마치 버그 인 것처럼 눈에 띄게 줄어 듭니다.
AntelopeSalad

2
Express Google 그룹 출신이었습니다. 링크는 다음과 같습니다. groups.google.com/group/express-js/browse_thread/thread/…
AntelopeSalad

52
아니 이것은 사실이 아니다
tjholowaychuk

답변:


306

좋아, 그것은 오랜 시간이 지났고 이것은 인기있는 질문입니다. 그래서 JavaScript 코드와 중간 크기의 express.js 응용 프로그램을 구성하는 방법에 대한 긴 README가있는 스캐 폴딩 github 저장소를 만들었습니다.

focusaurus / express_code_structure 는 최신 코드가 포함 된 저장소입니다. 풀 요청을 환영합니다.

다음은 README의 스냅 샷입니다. 스택 오버플로는 링크 응답 만 좋아하지 않습니다. 나는 이것이 계속 업데이트 할 새로운 프로젝트이므로 업데이트 할 것이지만 궁극적으로 github repo 가이 정보의 최신 장소가 될 것입니다.


익스프레스 코드 구조

이 프로젝트는 중간 크기의 express.js 웹 애플리케이션을 구성하는 방법의 예입니다.

현재 2016 년 12 월 v4.14 이상 표현

빌드 상태

JS 표준 스타일

응용 프로그램이 얼마나 큽니까?

웹 응용 프로그램이 모두 동일하지는 않으며 모든 express.js 응용 프로그램에 적용해야 할 단일 코드 구조는 없습니다.

응용 프로그램이 작은 경우 여기에 설명 된 것과 같은 깊은 디렉토리 구조가 필요하지 않습니다. 간단하게 유지하고 .js리포지토리의 루트에 소수의 파일을 집어 넣으면 완료됩니다. Voilà.

응용 프로그램이 크면 언젠가는 별도의 npm 패키지로 분리해야합니다. 일반적으로 node.js 접근 방식은 최소한 라이브러리에는 많은 작은 패키지를 선호하는 것으로 보이며 오버 헤드를 이해하고 이해하기 시작하는 여러 npm 패키지를 사용하여 응용 프로그램을 빌드해야합니다. 따라서 응용 프로그램이 커지고 코드의 일부가 응용 프로그램 외부에서 명확하게 재사용 가능하거나 명확한 하위 시스템이됨에 따라 자체 자식 저장소로 이동하여 독립형 npm 패키지로 만듭니다.

따라서이 프로젝트의 초점은 중형 응용 프로그램의 실행 가능한 구조를 설명하는 것입니다.

전반적인 아키텍처는 무엇입니까

웹 애플리케이션을 구축하는 방법에는 여러 가지가 있습니다.

  • 서버 측 MVC a la Ruby on Rails
  • 단일 페이지 응용 프로그램 스타일 및 MongoDB / Express / Angular / Node (MEAN)
  • 일부 형태의 기본 웹 사이트
  • la MVC이 (가) 죽은 모델 / 작업 / 뷰 / 이벤트 스타일, 이제 움직일 시간입니다
  • 그리고 다른 많은 사람들은 현재와 역사적인

이들 각각은 다른 디렉토리 구조에 잘 맞습니다. 이 예제의 목적 상, 그것은 비계 일 뿐이며 완전히 작동하는 앱은 아니지만 다음과 같은 주요 아키텍처 포인트를 가정합니다.

  • 이 사이트에는 전통적인 정적 페이지 / 템플릿이 있습니다
  • 사이트의 "응용 프로그램"부분은 단일 페이지 응용 프로그램 스타일로 개발되었습니다.
  • 애플리케이션은 REST / JSON 스타일 API를 브라우저에 노출합니다.
  • 이 앱은 간단한 비즈니스 도메인을 모델링합니다.이 경우 자동차 대리점 애플리케이션입니다.

그리고 Ruby on Rails는 어떻습니까?

이 프로젝트 전체에 걸쳐 주제가 될 것입니다. Ruby on Rails에서 구현 된 많은 아이디어와 그들이 채택한 "컨벤션 오버 컨벤션"결정은 실제로 널리 사용되지는 않았지만 실제로는 그다지 도움이되지 않으며 때로는이 리포지토리와 반대입니다. 추천합니다.

필자의 주요 요점은 코드 구성에 기본 원칙이 있으며, 이러한 원칙을 기반으로 Ruby on Rails 규칙은 Ruby on Rails 커뮤니티에 적합하다는 것입니다. 그러나 이러한 관습을 신중하게 숙지하는 것은 요점을 놓치게됩니다. 기본 원칙을 고수하면 셸 스크립트, 게임, 모바일 앱, 엔터프라이즈 프로젝트, 홈 디렉토리까지 모든 프로젝트가 잘 구성되고 명확 해집니다.

Rails 커뮤니티의 경우 단일 Rails 개발자가 앱에서 앱으로 전환하고 매번 익숙하고 편안하게 사용할 수 있기를 원합니다. 37 개의 신호 또는 Pivotal Labs에 적합하며 이점이 있습니다. 서버 측 JavaScript 세계에서 전반적인 정신은 훨씬 더 서구 적이며 실제로 문제가 없습니다. 그것이 우리가 굴리는 방식입니다. 우리는 그것에 익숙합니다. express.js에서도 Rails가 아닌 Sinatra와 밀접한 관계가 있으며 Rails에서 컨벤션을 취하는 것은 일반적으로 도움이되지 않습니다. 컨벤션에 대한 컨벤션에 대한 원칙 조차 말하고 싶습니다 .

기본 원칙과 동기

  • 정신적으로 관리 가능
    • 뇌는 한 번에 적은 수의 관련된 것들만 다루고 생각할 수 있습니다. 우리가 디렉토리를 사용하는 이유입니다. 작은 부분에 집중함으로써 복잡성을 처리하는 데 도움이됩니다.
  • 적절한 크기
    • 하나의 파일 만있는 3 개의 디렉토리가있는 "맨션 디렉토리"를 작성하지 마십시오. 3 개의 파일이있는 1 개의 디렉토리가 훨씬 더 적합 할 때 작은 프로젝트가 10 개 이상의 디렉토리를 작성하여 10 개 이상의 파일을 보유하도록 하는 Ansible Best Practices 에서 이러한 일이 발생하는 것을 볼 수 있습니다 . 버스를 운전하지 말고 버스 운전을하지 않는 한 버스를 운전하지 마십시오. 실제 파일로 정당화되지 않는 파일 시스템 구조를 만들지 마십시오. .
  • 모듈 식이지만 실용적 임
    • 노드 커뮤니티는 전반적으로 작은 모듈을 선호합니다. 앱에서 완전히 분리 할 수있는 것은 모두 내부 용 또는 npm에 공개적으로 게시 할 수있는 모듈로 추출해야합니다. 그러나 여기에 해당하는 중간 규모의 응용 프로그램의 경우 오버 헤드로 인해 적절한 가치없이 워크 플로에 지루한 요소가 추가 될 수 있습니다. 따라서 완전히 분리 된 npm 모듈을 정당화하기에 충분하지 않은 일부 코드가 있는 경우에는 일부 크기 임계 값을 초과 할 때 추출 될 것으로 예상 되는 " 프로토 모듈 "을 고려하십시오 .
    • @ hij1nx 와 같은 일부 사람들 은 app/node_modules디렉토리를 포함 package.json하고 프로토 모듈 디렉토리에 파일을 가지고 있어 전환을 촉진하고 미리 알림으로 작동합니다.
  • 코드를 쉽게 찾을 수 있습니다
    • 빌드 할 기능이나 수정해야 할 버그가 있다면 개발자가 관련 소스 파일을 찾는 데 어려움을 겪지 않는 것이 목표입니다.
    • 이름은 의미 있고 정확합니다
    • crufty 코드가 완전히 제거되어 고아 파일에 남아 있거나 주석 처리되지 않았습니다.
  • 검색 친화적
    • 모든 자사 소스 코드가 app디렉토리에 있으므로 cdfind / grep / xargs / ag / ack / etc를 실행하고 타사 매치에 의해 방해받지 않을 수 있습니다
  • 간단하고 명백한 이름 사용
    • npm은 이제 모두 소문자 패키지 이름을 요구하는 것 같습니다. 나는 이것이 끔찍한 것을 발견하지만 무리를 따라야하므로 kebab-caseJavaScript의 변수 이름이 JavaScript 의 빼기 기호 camelCase이기 때문에 파일 이름을 사용해야 합니다 -.
    • 변수 이름은 모듈로의 기본 이름과 일치하지만,과은 kebab-case으로 변환camelCase
  • 기능별이 아닌 커플 링별 그룹화
    • 이의 루비 온 레일스 대회에서 중요한 출발이다 app/views, app/controllers, app/models, 등
    • 기능이 전체 스택에 추가되므로 기능과 관련된 전체 파일 스택에 중점을두고 싶습니다. 전화 번호 필드를 사용자 모델에 추가 할 때 사용자 컨트롤러 이외의 다른 컨트롤러는 신경 쓰지 않으며 사용자 모델 이외의 다른 모델은 신경 쓰지 않습니다.
    • 따라서 각각 자체 디렉토리에있는 6 개의 파일을 편집하고 해당 디렉토리에있는 수많은 다른 파일을 무시하는 대신이 저장소는 기능을 빌드하는 데 필요한 모든 파일이 함께 배치되도록 구성됩니다.
    • MVC의 특성상, 사용자 뷰는 사용자 모델에 연결된 사용자 컨트롤러에 연결된다. 따라서 사용자 모델을 변경하면이 3 개의 파일이 함께 변경되는 경우가 많지만 거래 컨트롤러 또는 고객 컨트롤러는 분리되어 관련되지 않습니다. 비 MVC 설계에도 동일하게 적용됩니다.
    • 어떤 코드가 어떤 모듈에 권장되는지에 대한 MVC 또는 MOVE 스타일 디커플링은 여전히 ​​MVC 파일을 형제 디렉토리에 퍼뜨리는 것은 성가신 일입니다.
    • 따라서 내 각 라우트 파일에는 자신이 소유 한 라우트의 일부가 있습니다. 레일 스타일 routes.rb파일은 앱의 모든 경로에 대한 개요를 원할 경우 편리하지만 실제로 기능을 빌드하고 버그를 수정하는 경우 변경하는 부분과 관련된 경로 만 신경 써야합니다.
  • 코드 옆에 테스트 저장
    • 이것은 "group by coupling"의 인스턴스 일 뿐이지 만, 구체적으로 설명하고 싶었습니다. 테스트가 "tests"라는 병렬 파일 시스템 하에서 진행되는 많은 프로젝트를 작성했으며 이제는 해당 코드와 동일한 디렉토리에 테스트를 시작 했으므로 결코 되돌아 가지 않을 것입니다. 이것은 텍스트 편집기에서보다 모듈화되고 작업하기가 훨씬 쉬우 며 많은 "../../ .."경로 넌센스를 완화합니다. 확실치 않은 경우 몇 가지 프로젝트를 시도해보고 스스로 결정하십시오. 나는 그것이 더 낫다는 것을 확신시키기 위해 이것 이외의 어떤 것도하지 않을 것입니다.
  • 이벤트와 교차 절단 커플 링 감소
    • "새 거래가 생성 될 때마다 모든 영업 사원에게 전자 메일을 보내려고합니다"라고 생각한 다음 거래를 생성하는 경로에 해당 전자 메일을 보내는 코드 만 넣으면됩니다.
    • 그러나이 커플 링은 결국 앱을 거대한 진흙 공으로 바꿉니다.
    • 대신, DealModel은 "만들기"이벤트를 발생시키고 시스템이 그에 대한 응답으로 시스템이 수행 할 수있는 작업을 완전히 인식하지 않아야합니다.
    • 이 방법으로 코딩 app/users하면 사용자 코드 기반의 순도를 오염시키는 모든 장소에 연결된 비즈니스 로직의 랫트가 없기 때문에 모든 사용자 관련 코드를 넣을 수 있습니다 .
  • 코드 흐름에 따름
    • 마법적인 일을하지 마십시오. 파일 시스템의 매직 디렉토리에서 파일을 자동로드하지 마십시오. Rails가되지 마십시오. 앱이 시작되고 app/server.js:1코드를 따라로드 및 실행되는 모든 것을 볼 수 있습니다.
    • 경로에 DSL을 만들지 마십시오. 부적절하게 메타 프로그래밍을하지 마십시오.
    • 앱이 일을 너무 큰 경우 magicRESTRouter.route(somecontroller, {except: 'POST'})큰 승리를위한 이상 3 기본 app.get, app.put, app.del, 전화, 당신은 아마 효율적으로 작업 할 너무 커서 모 놀리 식 응용 프로그램을 구축하고 있습니다. 3 개의 간단한 라인을 1 개의 복잡한 라인으로 변환하는 것이 아니라 BIG의 승리를 위해 공감하십시오.
  • 케밥 소문자 파일 이름 사용

    • 이 형식은 플랫폼에서 파일 시스템 대소 문자 구분 문제를 방지합니다
    • npm은 새 패키지 이름에서 대문자를 금지하며 이는 잘 작동합니다.

      express.js 사양

  • 를 사용하지 마십시오 app.configure. 거의 완전히 쓸모가 없으며 필요하지 않습니다. 마음이없는 카피 파스타로 인해 많은 상용구에 있습니다.

  • 미들웨어 주문 및 특급 사안의 경로 !!!
    • stackoverflow에서 볼 수있는 거의 모든 라우팅 문제는 고장난 표현 미들웨어입니다.
    • 일반적으로 경로를 분리하고 순서에 의존하지 않기를 원합니다.
    • app.use2 개의 경로에 해당 미들웨어 만 필요한 경우 전체 애플리케이션에 사용하지 마십시오 (내가보고 있습니다 body-parser).
    • 모든 내용을 말하고 완료했는지 확인하십시오.
      1. 매우 중요한 애플리케이션 전체 미들웨어
      2. 모든 경로 및 여러 경로 미들웨어
      3. THEN 오류 처리기
  • 슬프게도, sinatra에서 영감을 얻은 express.js는 대부분 모든 경로가있을 것으로 가정하고 server.js주문 방식이 명확합니다. 중간 규모의 응용 프로그램의 경우 별도의 경로 모듈로 분류하는 것이 좋지만 고장난 미들웨어의 위험을 초래합니다.

앱 심볼릭 트릭

Node.js에 대한 더 나은 local require () 경로 에서 커뮤니티가 길게 설명하고 논의한 많은 접근 방식이 있습니다 . 나는 곧 "많은 ../../../ .. 다루기"를 원하거나 requireFrom 모듈을 사용하기로 결정할 수도있다. 그러나 현재는 아래에 설명 된 symlink 트릭을 사용하고 있습니다.

따라서 프로젝트 내에서 요구하는 성가신 상대 경로를 피하는 한 가지 방법 require("../../../config")은 다음 트릭을 사용하는 것입니다.

  • 앱의 node_modules 아래에 심볼릭 링크를 만듭니다
    • cd node_modules && ln -nsf ../app
  • git에 전체 node_modules 폴더가 아닌 node_modules / app symlink 자체를 추가하십시오.
    • git add -f node_modules / app
    • 예, 여전히 .gitignore파일 에 "node_modules"가 있어야 합니다
    • 아니요, "node_modules"를 git 저장소에 넣지 마십시오. 어떤 사람들은 이것을 권장합니다. 잘못되었습니다.
  • 이제이 접두사를 사용하여 프로젝트 내 모듈을 요구할 수 있습니다
    • var config = require("app/config");
    • var DealModel = require("app/deals/deal-model");
  • 기본적으로 이것은 프로젝트 내부 요구 사항을 외부 npm 모듈 요구 사항과 매우 유사하게 만듭니다.
  • 죄송합니다. Windows 사용자는 상위 디렉토리 상대 경로를 사용해야합니다.

구성

일반적으로 기본 JavaScript options객체 만 전달 되도록 모듈 및 클래스를 코딩하십시오. 모듈 만 app/server.js로드해야 app/config.js합니다. 거기에서 options필요에 따라 작은 오브젝트를 합성 하여 서브 시스템을 구성 할 수 있지만, 모든 서브 시스템을 추가 정보로 가득 찬 큰 전역 구성 모듈에 결합하는 것은 나쁜 결합입니다.

연결 매개 변수를 전달하고 서브 시스템이 나가는 연결을 작성하는 것과 달리 DB 연결 작성을 중앙 집중화하여 서브 시스템으로 전달하십시오.

NODE_ENV

이것은 Rails에서 가져온 또 다른 유혹이지만 끔찍한 아이디어입니다. 앱에 정확히 1 개의 위치가 있어야하며 app/config.js, NODE_ENV환경 변수 를 살펴 봅니다 . 그 밖의 모든 것에는 클래스 생성자 인수 또는 모듈 구성 매개 변수로 명시적인 옵션을 사용해야합니다.

이메일 모듈에 이메일 전달 방법 (SMTP, stdout에 로그, 대기열에 넣는 방법 등)에 대한 옵션이있는 경우에는 옵션을 선택 {deliver: 'stdout'}해야하지만 반드시 확인해서는 안됩니다 NODE_ENV.

테스트

이제 테스트 파일을 해당 코드와 동일한 디렉토리에 유지하고 파일 이름 확장명 명명 규칙을 사용하여 테스트와 프로덕션 코드를 구분합니다.

  • foo.js "foo"모듈 코드가 있습니다
  • foo.tape.js foo에 대한 노드 기반 테스트가 있으며 동일한 디렉토리에 있습니다.
  • foo.btape.js 브라우저 환경에서 실행해야하는 테스트에 사용할 수 있습니다.

파일 시스템 글로브와 find . -name '*.tape.js'명령을 사용하여 필요에 따라 모든 테스트에 액세스합니다.

.js모듈 파일 내에서 코드를 구성하는 방법

이 프로젝트의 범위는 주로 파일과 디렉토리의 위치에 관한 것이며 다른 범위를 추가하고 싶지는 않지만 코드를 3 개의 개별 섹션으로 구성한다고 언급합니다.

  1. CommonJS의 시작 블록은 상태 종속성에 대한 호출이 필요합니다.
  2. 순수 자바 스크립트의 메인 코드 블록. 여기에 CommonJS 오염이 없습니다. 내보내기, 모듈 또는 필요를 참조하지 마십시오.
  3. 내보내기를 설정하기위한 CommonJS의 닫기 블록

1
사용하는 경로가 적은 경우 bodyParser 대신 무엇을 사용해야합니까?
Ilan Frumer

3
여기에서 내가 찾던 것을 발견했습니다 : stackoverflow.com/questions/12418372/…
Ilan Frumer

1
@wlingke 확인 gist.github.com/branneman/8048520을 그 문제에 대한 가능한 접근 방법의 철저한 토론.
Peter Lyons

@peterLyons 공유해 주셔서 감사합니다. 읽은 후에 시작 스크립트를 작성한다고 생각합니다. 감사!
wlingke

2
받는 사람 관련하여 응용 심볼릭 링크 트릭 , 거기에 모든 문제가 사라 만드는 작은 모듈
헤이 코 코련

157

업데이트 (2013-10-29) : 인기있는 요구에 따라 CoffeeScript 대신 JavaScript가 있고 상용구 github 저장소 및이 주제에 대한 최신 권장 사항을 자세히 설명하는 광범위한 README가있는 다른 대답도 참조하십시오.

구성

당신이하는 일은 괜찮습니다. 내 자신의 구성 네임 스페이스를 config.coffee중첩 네임 스페이스가있는 최상위 파일 에 설정하고 싶습니다.

#Set the current environment to true in the env object
currentEnv = process.env.NODE_ENV or 'development'
exports.appName = "MyApp"
exports.env =
  production: false
  staging: false
  test: false
  development: false
exports.env[currentEnv] = true
exports.log =
  path: __dirname + "/var/log/app_#{currentEnv}.log"
exports.server =
  port: 9600
  #In staging and production, listen loopback. nginx listens on the network.
  ip: '127.0.0.1'
if currentEnv not in ['production', 'staging']
  exports.enableTests = true
  #Listen on all IPs in dev/test (for testing from other machines)
  exports.server.ip = '0.0.0.0'
exports.db =
  URL: "mongodb://localhost:27017/#{exports.appName.toLowerCase()}_#{currentEnv}"

이것은 sysadmin 편집에 친숙합니다. 그런 다음 DB 연결 정보와 같은 것이 필요할 때

require('./config').db.URL

경로 / 컨트롤러

나는 내 경로를 컨트롤러와 함께두고 app/controllers하위 디렉토리에 구성하는 것을 좋아합니다 . 그런 다음로드하여 필요한 경로를 추가 할 수 있습니다.

app/server.coffee커피 스크립트 파일에서 나는 :

[
  'api'
  'authorization'
  'authentication'
  'domains'
  'users'
  'stylesheets'
  'javascripts'
  'tests'
  'sales'
].map (controllerName) ->
  controller = require './controllers/' + controllerName
  controller.setup app

그래서 다음과 같은 파일이 있습니다.

app/controllers/api.coffee
app/controllers/authorization.coffee
app/controllers/authentication.coffee
app/controllers/domains.coffee

예를 들어 내 도메인 컨트롤러에는 setup다음과 같은 기능이 있습니다.

exports.setup = (app) ->
  controller = new exports.DomainController
  route = '/domains'
  app.post route, controller.create
  app.put route, api.needId
  app.delete route, api.needId
  route = '/domains/:id'
  app.put route, controller.loadDomain, controller.update
  app.del route, controller.loadDomain, exports.delete
  app.get route, controller.loadDomain, (req, res) ->
    res.sendJSON req.domain, status.OK

견해

뷰를 넣는 app/views것이 관습적인 장소가되고 있습니다. 나는 이것을 이렇게 배치했습니다.

app/views/layout.jade
app/views/about.jade
app/views/user/EditUser.jade
app/views/domain/EditDomain.jade

정적 파일

public서브 디렉토리로 이동하십시오 .

Github / Semver / NPM

github의 git repo 루트에 README.md 마크 다운 파일을 넣으십시오.

시맨틱 버전 번호가 있는 package.json 파일 을 NPM의 git repo 루트에 넣으십시오 .


1
안녕 피터! 나는 당신이 가고있는이 접근법을 정말로 좋아합니다. 나는 급행 프로젝트를 구축하고 있으며 실제로 해킹하고 배치하는 것보다 올바른 방법으로 일하고 싶습니다. github 및 / 또는 블로그 게시물에 샘플 저장소가 있으면 훌륭합니다.
suVasH .....

4
이 저장소에는 참조로 사용할 수있는 패턴이 많이 있습니다. github.com/focusaurus/peterlyons.com
Peter Lyons

75
커피 스크립트는 이것을 읽기 어렵게 만듭니다 : / 바닐라 JS를 편집 할 수있는 기회가 있습니까? 감사합니다
toasted_flakes

1
이 답변에 감사드립니다. 나는 단지 내 마음을 감싸려고합니다. 다른 컨트롤러 내부의 다른 컨트롤러에 어떻게 액세스합니까 (예 : 위와 같은 설정 기능app.put route, api.needId
chmanie

@ PeterLyons : 안녕하세요, 소스 코드를 보았지만 빌드 모드를 수행하는 방법을 모릅니다. 이미 파일을 설치 Go하고 bin구조에 포함 시켰습니다. 그 go파일을 bin어떻게 실행 합니까?
user2002495

51

다음은 다른 사람들의 요청에 따라 Coffeescript의 바닐라 JS로 포팅 된 Peter Lyons의 대답입니다. Peter의 답변은 매우 유능하며 내 답변에 투표하는 사람은 누구나 투표해야합니다.


구성

당신이하는 일은 괜찮습니다. 내 자신의 구성 네임 스페이스를 config.js중첩 네임 스페이스가있는 최상위 파일 에 설정하고 싶습니다.

// Set the current environment to true in the env object
var currentEnv = process.env.NODE_ENV || 'development';
exports.appName = "MyApp";
exports.env = {
  production: false,
  staging: false,
  test: false,
  development: false
};  
exports.env[currentEnv] = true;
exports.log = {
  path: __dirname + "/var/log/app_#{currentEnv}.log"
};  
exports.server = {
  port: 9600,
  // In staging and production, listen loopback. nginx listens on the network.
  ip: '127.0.0.1'
};  
if (currentEnv != 'production' && currentEnv != 'staging') {
  exports.enableTests = true;
  // Listen on all IPs in dev/test (for testing from other machines)
  exports.server.ip = '0.0.0.0';
};
exports.db {
  URL: "mongodb://localhost:27017/#{exports.appName.toLowerCase()}_#{currentEnv}"
};

이것은 sysadmin 편집에 친숙합니다. 그런 다음 DB 연결 정보와 같은 것이 필요할 때

require('./config').db.URL

경로 / 컨트롤러

나는 내 경로를 컨트롤러와 함께두고 app/controllers하위 디렉토리에 구성하는 것을 좋아합니다 . 그런 다음로드하여 필요한 경로를 추가 할 수 있습니다.

app/server.js자바 스크립트 파일에서 나는 :

[
  'api',
  'authorization',
  'authentication',
  'domains',
  'users',
  'stylesheets',
  'javascripts',
  'tests',
  'sales'
].map(function(controllerName){
  var controller = require('./controllers/' + controllerName);
  controller.setup(app);
});

그래서 다음과 같은 파일이 있습니다.

app/controllers/api.js
app/controllers/authorization.js
app/controllers/authentication.js
app/controllers/domains.js

예를 들어 내 도메인 컨트롤러에는 setup다음과 같은 기능이 있습니다.

exports.setup = function(app) {
  var controller = new exports.DomainController();
  var route = '/domains';
  app.post(route, controller.create);
  app.put(route, api.needId);
  app.delete(route, api.needId);
  route = '/domains/:id';
  app.put(route, controller.loadDomain, controller.update);
  app.del(route, controller.loadDomain, function(req, res){
    res.sendJSON(req.domain, status.OK);
  });
}

견해

뷰를 넣는 app/views것이 관습적인 장소가되고 있습니다. 나는 이것을 이렇게 배치했습니다.

app/views/layout.jade
app/views/about.jade
app/views/user/EditUser.jade
app/views/domain/EditDomain.jade

정적 파일

public서브 디렉토리로 이동하십시오 .

Github / Semver / NPM

github의 git repo 루트에 README.md 마크 다운 파일을 넣으십시오.

시맨틱 버전 번호가 있는 package.json 파일 을 NPM의 git repo 루트에 넣으십시오 .


43

내 질문은 2011 년 4 월에 소개되었으며 조용합니다. 이 기간 동안 Express.js에 대한 경험과이 라이브러리를 사용하여 작성된 응용 프로그램을 아키텍처 화하는 방법을 향상시킬 수있었습니다. 그래서 나는 여기 내 경험을 공유합니다.

내 디렉토리 구조는 다음과 같습니다.

├── app.js   // main entry
├── config   // The configuration of my applications (logger, global config, ...)
├── models   // The model data (e.g. Mongoose model)
├── public   // The public directory (client-side code)
├── routes   // The route definitions and implementations
├── services // The standalone services (Database service, Email service, ...)
└── views    // The view rendered by the server to the client (e.g. Jade, EJS, ...)

App.js

app.js파일 의 목표 는 expressjs 애플리케이션을 부트 스트랩하는 것입니다. 구성 모듈, 로거 모듈을로드하고 데이터베이스 연결을 기다립니다 ... 및 Express 서버를 실행합니다.

'use strict';
require('./config');
var database = require('./services/database');
var express = require('express');
var app = express();
module.exports = app;

function main() {
  var http = require('http');

  // Configure the application.
  app.configure(function () {
    // ... ... ...
  });
  app.configure('production', function () {
    // ... ... ...
  });
  app.configure('development', function () {
    // ... ... ...
  });

  var server = http.createServer(app);

  // Load all routes.
  require('./routes')(app);

  // Listen on http port.
  server.listen(3000);
}

database.connect(function (err) {
  if (err) { 
    // ...
  }
  main();
});

노선 /

routes 디렉토리에 index.js파일이 있습니다. 그것의 목표는 routes/디렉토리에 다른 모든 파일을로드하는 일종의 마술을 도입하는 것입니다 . 구현은 다음과 같습니다.

/**
 * This module loads dynamically all routes modules located in the routes/
 * directory.
 */
'use strict';
var fs = require('fs');
var path = require('path');

module.exports = function (app) {
  fs.readdirSync('./routes').forEach(function (file) {
    // Avoid to read this current file.
    if (file === path.basename(__filename)) { return; }

    // Load the route file.
    require('./' + file)(app);
  });
};

이 모듈을 사용하면 새로운 경로 정의 및 구현을 만드는 것이 정말 쉽습니다. 예를 들면 다음과 hello.js같습니다.

function hello(req, res) {
  res.send('Hello world');
}

module.exports = function (app) {
  app.get('/api/hello_world', hello);
};

각 경로 모듈은 독립형 입니다.


생성기를 사용하여이 구조를 작성합니까?
Ashish


17

나는 그것을하는 좋은 방법이라고 생각합니다. 표현에 국한되지는 않지만 github에서 꽤 많은 node.js 프로젝트가 동일한 작업을 수행하는 것을 보았습니다. 그들은 구성 매개 변수를 취합니다 + 작은 모듈 (경우에 따라 모든 URI)은 별도의 파일에 포함됩니다.

아이디어를 얻으려면 github에서 특정 프로젝트를 진행하는 것이 좋습니다. IMO는 당신이하고있는 방식이 맞습니다.


16

이제 2015 년 말 이며 3 년 동안 크고 작은 프로젝트에서 내 구조를 개발 한 후입니다. 결론?

하나의 큰 MVC를 수행하지 말고 모듈로 분리하십시오.

그래서...

왜?

  • 일반적으로 하나의 모듈 (예 : 제품)에서 작동하며 독립적으로 변경할 수 있습니다.

  • 모듈을 재사용 할 수 있습니다

  • 별도로 테스트 할 수 있습니다

  • 별도로 교체 할 수 있습니다

  • 그들은 명확한 (안정한) 인터페이스를 가지고 있습니다

    -최근에 여러 개발자가 작업하고 있다면 모듈 분리가 도움이됩니다.

nodebootstrap의 프로젝트 내 최종 구조와 유사한 접근 방식을 가지고있다. ( github )

이 구조는 어떻게 생겼습니까?

  1. 각각 별도의 MVC가있는 소형 캡슐화 된 모듈

  2. 각 모듈 에는 패키지가 있습니다.

  3. 구조의 일부로 테스트 (각 모듈에서)

  4. 글로벌 구성 , 라이브러리 및 서비스

  5. 통합 도커, 클러스터, 영원히

폴더 개요 (모듈은 lib 폴더 참조) :

nodebootstrap 구조


3
개별 모듈을 확장 한 상태에서 폴더 개요 그림을 업데이트하고 구성하는 방법의 예도 도움이됩니다.
youngrrrr

8

MVC 스타일의 폴더 구조를 제공하고 있습니다.

우리는 중소 규모의 웹 응용 프로그램에 다음과 같은 폴더 구조를 사용했습니다.

 myapp   
|
|
|____app
|      |____controllers
|      |    |____home.js
|      |
|      |____models
|      |     |___home.js
|      |
|      |____views
|           |___404.ejs
|           |___error.ejs
|           |___index.ejs
|           |___login.ejs
|           |___signup.ejs
|   
|
|_____config
|     |___auth.js
|     |___constants.js
|     |___database.js
|     |___passport.js
|     |___routes.js
|
|
|____lib
|    |___email.js
|
|____node_modules
|
|
|____public.js
|    |____css
|    |    |__style.css
|    |    
|    |____js
|    |    |__script.js
|    |
|    |____img
|    |    |__img.jpg
|    |
|    |
|    |____uploads
|         |__img.jpg
|      
|   
|
|_____app.js
|
|
|
|_____package.json

Express mvc 폴더 구조 생성을 위해 하나의 npm 모듈을 만들었습니다.

다음을 찾으십시오. https://www.npmjs.com/package/express-mvc-generator

이 모듈을 생성하고 사용하는 간단한 단계입니다.

i) 모듈 설치 npm install express-mvc-generator -g

ii) 옵션 확인 express -h

iii) Express mvc 구조 생성 express myapp

iv) 설치 종속성 : npm install:

v) config / database.js를 열고 mongo db를 구성하십시오.

vi) 응용 프로그램을 실행 node app하거나nodemon app

vii) URL http : // localhost : 8042 / signup 또는 http : // yourip : 8042 / signup을 확인하십시오.


7

이 질문에 대한 마지막 답변 이후 꽤 오래되었으며 Express는 최근에 버전 4를 출시하여 앱 구조를 구성하는 데 유용한 몇 가지 사항을 추가했습니다.

다음은 Express 앱을 구성하는 방법에 대한 모범 사례에 대한 최신 블로그 게시물입니다. http://www.terlici.com/2014/08/25/best-practices-express-structure.html

기사에 조언을 적용하는 GitHub 리포지토리도 있습니다. 항상 최신 Express 버전으로 최신 상태입니다.
https://github.com/terlici/base-express


7

구성에 경로를 추가하는 것이 좋은 방법이라고 생각하지 않습니다. 더 나은 구조는 다음과 같습니다.

application/
| - app.js
| - config.js
| - public/ (assets - js, css, images)
| - views/ (all your views files)
| - libraries/ (you can also call it modules/ or routes/)
    | - users.js
    | - products.js
    | - etc...

따라서 products.js와 users.js에는 모든 경로가 포함되어 모든 논리가 포함됩니다.


6

글쎄, 나는 처음에 읽은 json 파일로 경로를 넣고 app.js의 for 루프에서 경로를 설정했다. route.json은 호출해야하는보기와 경로로 전송 될 값의 키를 포함합니다.
이것은 많은 간단한 경우에 작동하지만 특수한 경우에 대한 경로를 수동으로 만들어야했습니다.


6

나는이 문제에 대해 정확하게 게시물을 작성했습니다. 기본적으로 함수를 호출 routeRegistrar하는 폴더의 파일을 반복하는를 사용 /controllers합니다 init. 함수 init는 표현 app변수를 매개 변수로 사용하므로 원하는 방식으로 경로를 등록 할 수 있습니다.

var fs = require("fs");
var express = require("express");
var app = express();

var controllersFolderPath = __dirname + "/controllers/";
fs.readdirSync(controllersFolderPath).forEach(function(controllerName){
    if(controllerName.indexOf("Controller.js") !== -1){
        var controller = require(controllersFolderPath + controllerName);
        controller.init(app);
    }
});

app.listen(3000);


4

1) Express 프로젝트 파일 시스템은 다음과 같습니다.

/ ...
/lib
/node_modules
/public
/views
      app.js
      config.json
      package.json

app.js-글로벌 앱 컨테이너

2) 모듈 메인 파일 (lib / mymodule / index.js) :

var express = require('express');    
var app = module.exports = express();
// and load module dependencies ...  

// this place to set module settings
app.set('view engine', 'jade');
app.set('views', __dirname + '/views');

// then do module staff    
app.get('/mymodule/route/',function(req,res){ res.send('module works!') });

3) 메인 app.js에서 모듈 연결

...
var mymodule = require('mymodule');
app.use(mymodule);

4) 샘플 로직

lib/login
lib/db
lib/config
lib/users
lib/verify
lib/
   /api/ 
   ...
lib/
   /admin/
      /users/
      /settings/
      /groups/
...
  • 테스트에 최적
  • 규모에 가장 적합
  • 모듈에 따라 분리
  • 기능 (또는 모듈)별로 경로 그룹화

tj Vimeo에 대한 흥미로운 아이디어에 대한 표현 은 Node.js 및 Express를 사용하여 익스프레스 애플리케이션 모듈 형 웹 애플리케이션을 모듈화하는 방법에 대한 흥미로운 아이디어 입니다. 강력하고 간단합니다.


4

http://locomotivejs.org/ 는 Node.js 및 Express로 빌드 된 앱을 구성하는 방법을 제공합니다.

웹 사이트에서 :

Locomotive는 Node.js의 웹 프레임 워크입니다. Locomotive는 MVC 패턴, RESTful 라우트 및 구성에 대한 컨벤션을 지원하면서 모든 데이터베이스 및 템플릿 엔진과 완벽하게 통합됩니다. 노드에서. "


3

최근에 모듈을 독립 미니 앱으로 받아 들였습니다.

|-- src
  |--module1
  |--module2
     |--www
       |--img
       |--js
       |--css
     |--#.js
     |--index.ejs
  |--module3
  |--www
     |--bower_components
     |--img
     |--js
     |--css
  |--#.js
  |--header.ejs
  |--index.ejs
  |--footer.ejs

이제 모든 모듈 라우팅 (# .js)에 대해 뷰 (* .ejs), js, css 및 자산이 나란히 있습니다. 서브 모듈 라우팅은 두 개의 추가 라인이있는 상위 # .js에 설정됩니다.

router.use('/module2', opt_middleware_check, require('./module2/#'));
router.use(express.static(path.join(__dirname, 'www')));

이런 식으로 하위 서브 모듈도 가능합니다.

src 디렉토리로보기를 설정하는 것을 잊지 마십시오

app.set('views', path.join(__dirname, 'src'));

루트, 뷰 및 모델의로드 방법에 관심이있는 구조를 가진 github에 대한 링크
Muhammad Umer

모든 것이 설명되어 있다고 생각합니다. 경로는 고전적인 특급 경로입니다. 뷰는 모듈 이름으로 접두사를로드해야하고 상대 경로를 참조하여 모델을로드해야합니다.
zevero

마지막 줄에서 뷰를 src 디렉토리로 설정했습니다. 여기서부터 모든 뷰는 src 디렉토리와 관련하여 액세스 할 수 있습니다. 멋진 것은 없습니다.
zevero

1

이것이 내 Express 프로젝트 디렉토리 구조의 대부분입니다.

나는 보통 express dirname프로젝트를 초기화하고 게으름을 용서하지만 매우 유연하고 확장 가능합니다. 추신-당신은 그것을 얻을 express-generator필요가 있습니다 (찾는 사람들을 위해 sudo npm install -g express-generator, 전 세계적으로 설치하기 때문에 sudo)

|-- bin
    |-- www //what we start with "forever"
|-- bower_components
|-- models
    |-- database.js
    |-- model1.js //not this exact name ofcourse.
    |-- .
|-- node_modules
|-- public
    |-- images
    |-- javascripts
        |-- controllers
        |-- directives
        |-- services
        |-- app.js
        |-- init.js //contains config and used for initializing everything, I work with angular a lot.
    |-- stylesheets
|-- routes
    |-- some
    |-- hierarchy
    .
    .
|-- views
    |-- partials
    |-- content
|-- .env
|-- .env.template
|-- app.js
|-- README.md

.env 파일이 왜 궁금하십니까? 그들이 작동하기 때문에! 나는 사용한다dotenv내 프로젝트에서 (최근에) 모듈을 하고 작동합니다! 이 두 문장에서 app.js또는www

var dotenv = require('dotenv');
dotenv.config({path: path.join(__dirname + "/.env")});

그리고 /bower_components리소스 아래에서 정적 콘텐츠를 제공 하도록 빠르게 설정 하는 또 다른 줄/ext

app.use('/ext', express.static(path.join(__dirname, 'bower_components')));

Express와 Angular를 함께 사용하거나 javascripts계층 구조 없이 표현하려는 사람들에게 적합 할 수 있습니다 .


1

내 구조 표현 4. https://github.com/odirleiborgert/borgert-express-boilerplate

패키지

View engine: twig
Security: helmet
Flash: express-flash
Session: express-session
Encrypt: bcryptjs
Modules: express-load
Database: MongoDB
    ORM: Mongoose
    Mongoose Paginate
    Mongoose Validator
Logs: winston + winston-daily-rotate-file
Nodemon
CSS: stylus
Eslint + Husky

구조

|-- app
    |-- controllers
    |-- helpers
    |-- middlewares
    |-- models
    |-- routes
    |-- services
|-- bin
|-- logs
|-- node_modules
|-- public
    |-- components
    |-- images
    |-- javascripts
    |-- stylesheets
|-- views
|-- .env
|-- .env-example
|-- app.js
|-- README.md

0

ur Express 앱을 구성하는 간단한 방법 :

  • main index.js에서 다음 순서를 유지해야합니다.

    모든 app.set 이 먼저 있어야합니다.

    모든 app.use 는 두 번째이어야합니다.

    기능이있는 다른 API가 뒤 따르거나 다른 파일에서 경로 연속

    Exapmle

    app.use ( "/ password", passwordApi);

    app.use ( "/ user", userApi);

    app.post ( "/ token", passport.createToken);

    app.post ( "/ logout", passport.logout)


0

핸들 바 및 Passportjs를 사용하는 ExpressJs 프로젝트의 MVC 구조에 대한 가장 좋은 방법

- app
      -config 
        -passport-setup.js
      -controllers
      -middleware
      -models
      -routes
      -service
    -bin
      -www
      -configuration.js
      -passport.js
    -node_modules
    -views
     -handlebars page
    -env
    -.gitignore
    -package.json
    -package-lock.json

@ sandro-munda 확인하십시오
Manishkumar Bhavnani
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.