ExpressJS Bagaimana cara menyusun aplikasi?


527

Saya menggunakan kerangka kerja ExpressJS untuk NodeJS.

Orang yang menggunakan ExpressJS menempatkan lingkungan mereka (pengembangan, produksi, pengujian ...), rute mereka dll pada app.js. Saya pikir itu bukan cara yang indah karena ketika Anda memiliki aplikasi besar, app.js terlalu besar!

Saya ingin memiliki struktur direktori ini:

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

Ini kode saya:

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 / route.js

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

Kode saya berfungsi dengan baik dan saya pikir struktur direktori itu indah. Namun, kode harus diadaptasi dan saya tidak yakin itu bagus / cantik.

Apakah lebih baik menggunakan struktur direktori saya dan mengadaptasi kode atau hanya menggunakan satu file (app.js)?

Terima kasih atas saran Anda!


Apakah masalah kinerja melakukannya dengan cara ini masih mengintai? Saya ingat pernah membaca di suatu tempat (mungkin grup ekspres) bahwa ketika Anda memisahkan semuanya seperti ini, Anda kehilangan banyak kinerja. Sesuatu seperti reqs / detik Anda akan turun dengan jumlah yang nyata, hampir seolah-olah itu adalah bug.
AntelopeSalad

2
Itu dari grup Google Express. Inilah tautannya: groups.google.com/group/express-js/browse_thread/thread/…
AntelopeSalad

52
tidak ini sangat tidak benar
tjholowaychuk

Jawaban:


306

OK, sudah lama dan ini adalah pertanyaan yang populer, jadi saya sudah maju dan membuat repositori github perancah dengan kode JavaScript dan README panjang tentang bagaimana saya ingin menyusun aplikasi express.js berukuran sedang.

focusaurus / express_code_structure adalah repo dengan kode terbaru untuk ini. Permintaan tarik diterima.

Ini snapshot README karena stackoverflow tidak menyukai jawaban hanya tautan. Saya akan membuat beberapa pembaruan karena ini adalah proyek baru yang akan saya terus perbarui, tetapi akhirnya repo github akan menjadi tempat terbaru untuk informasi ini.


Struktur Kode Ekspres

Proyek ini adalah contoh bagaimana mengatur aplikasi web express.js berukuran sedang.

Saat ini untuk setidaknya mengekspresikan v4.14 Desember 2016

Status Bangun

js-standar-gaya

Seberapa besar aplikasi Anda?

Aplikasi web tidak semuanya sama, dan menurut saya, tidak ada struktur kode tunggal yang harus diterapkan untuk semua aplikasi express.js.

Jika aplikasi Anda kecil, Anda tidak perlu struktur direktori yang dalam seperti yang dicontohkan di sini. Tetap sederhana dan tempelkan beberapa .jsfile di root repositori Anda dan Anda selesai. Voa.

Jika aplikasi Anda besar, pada titik tertentu Anda perlu memecahnya menjadi paket npm yang berbeda. Secara umum pendekatan node.js tampaknya mendukung banyak paket kecil, setidaknya untuk pustaka, dan Anda harus membangun aplikasi Anda dengan menggunakan beberapa paket npm karena itu mulai masuk akal dan membenarkan overhead. Jadi ketika aplikasi Anda tumbuh dan sebagian kode menjadi jelas dapat digunakan kembali di luar aplikasi Anda atau merupakan subsistem yang jelas, pindahkan ke repositori git itu sendiri dan buatlah menjadi paket npm mandiri.

Jadi fokus dari proyek ini adalah untuk menggambarkan struktur yang bisa diterapkan untuk aplikasi berukuran sedang.

Apa arsitektur keseluruhan Anda

Ada banyak pendekatan untuk membangun aplikasi web, seperti

  • Sisi Server MVC ala Ruby on Rails
  • Gaya Aplikasi Halaman Tunggal ala MongoDB / Express / Angular / Node (MEAN)
  • Situs web dasar dengan beberapa bentuk
  • Model / Operasi / Tampilan / Acara gaya a MVC sudah mati, saatnya untuk PINDAHKAN
  • dan banyak lainnya baik saat ini dan sejarah

Masing-masing cocok dengan baik ke dalam struktur direktori yang berbeda. Untuk keperluan contoh ini, ini hanya perancah dan bukan aplikasi yang berfungsi penuh, tapi saya mengasumsikan poin arsitektur utama berikut:

  • Situs ini memiliki beberapa halaman / templat statis tradisional
  • Bagian "aplikasi" dari situs ini dikembangkan sebagai gaya Aplikasi Halaman Tunggal
  • Aplikasi menampilkan API gaya REST / JSON ke browser
  • Aplikasi ini memodelkan domain bisnis sederhana, dalam hal ini, ini adalah aplikasi dealer mobil

Dan bagaimana dengan Ruby on Rails?

Ini akan menjadi tema di seluruh proyek ini bahwa banyak ide yang terkandung dalam Ruby on Rails dan keputusan "Konvensi Konfigurasi" yang telah mereka adopsi, meskipun diterima dan digunakan secara luas, sebenarnya tidak terlalu membantu dan kadang-kadang berlawanan dengan apa yang ada dalam repositori ini. merekomendasikan.

Poin utama saya di sini adalah bahwa ada prinsip-prinsip yang mendasari untuk mengatur kode, dan berdasarkan prinsip-prinsip itu, konvensi Ruby on Rails masuk akal (kebanyakan) untuk komunitas Ruby on Rails. Namun, hanya dengan menipu saja, konvensi-konvensi itu tidak tepat sasaran. Setelah Anda memahami prinsip-prinsip dasar, SEMUA proyek Anda akan terorganisir dengan baik dan jelas: skrip shell, game, aplikasi seluler, proyek perusahaan, bahkan direktori home Anda.

Untuk komunitas Rails, mereka ingin dapat memiliki satu pengembang Rails beralih dari satu aplikasi ke aplikasi dan menjadi akrab dan nyaman dengan itu setiap kali. Ini masuk akal jika Anda 37 sinyal atau Lab Penting, dan memiliki manfaat. Di dunia JavaScript sisi-server, etos keseluruhan hanyalah cara yang semakin liar dan kita tidak benar-benar memiliki masalah dengan itu. Begitulah cara kami menggulung. Kami sudah terbiasa. Bahkan di dalam express.js, ia adalah keluarga dekat Sinatra, bukan Rails, dan mengambil konvensi dari Rails biasanya tidak membantu apa pun. Saya bahkan akan mengatakan Principles over Convention over Configuration .

Prinsip dan Motivasi yang Mendasari

  • Dapat dikelola secara mental
    • Otak hanya dapat menangani dan memikirkan sejumlah kecil hal-hal terkait sekaligus. Itu sebabnya kami menggunakan direktori. Ini membantu kita menangani kompleksitas dengan berfokus pada porsi kecil.
  • Sesuai ukuran
    • Jangan membuat "Mansion Directories" di mana hanya ada 1 file sendirian 3 direktori di bawah. Anda dapat melihat ini terjadi di Ansible Best Practices yang memalukan proyek kecil untuk membuat 10+ direktori untuk menampung 10+ file ketika 1 direktori dengan 3 file akan jauh lebih tepat. Anda tidak mengendarai bus ke kantor (kecuali jika Anda seorang sopir bus, tetapi bahkan saat itu Anda mengendarai bus di tempat kerja tidak UNTUK), jadi jangan membuat struktur sistem file yang tidak dibenarkan oleh file aktual di dalamnya .
  • Bersifat modular tetapi pragmatis
    • Komunitas simpul secara keseluruhan mendukung modul-modul kecil. Apa pun yang dapat dipisahkan sepenuhnya dari aplikasi Anda sepenuhnya harus diekstraksi ke dalam modul baik untuk penggunaan internal atau dipublikasikan secara publik pada npm. Namun, untuk aplikasi berukuran sedang yang merupakan ruang lingkup di sini, overhead ini dapat menambah kebosanan pada alur kerja Anda tanpa nilai yang sepadan. Jadi untuk saat Anda memiliki beberapa kode yang difaktorkan tetapi tidak cukup untuk membenarkan modul npm yang benar-benar terpisah, anggap saja sebagai " proto-module " dengan harapan bahwa ketika melintasi beberapa ambang batas ukuran, itu akan diekstraksi.
    • Beberapa orang seperti @ hij1nx bahkan menyertakan app/node_modulesdirektori dan memiliki package.jsonfile dalam direktori proto-module untuk memfasilitasi transisi itu dan bertindak sebagai pengingat.
  • Mudah menemukan kode
    • Diberi fitur untuk membangun atau bug untuk memperbaikinya, tujuan kami adalah agar pengembang tidak kesulitan menemukan file sumber yang terlibat.
    • Nama bermakna dan akurat
    • kode crufty sepenuhnya dihapus, tidak ditinggalkan dalam file yatim atau hanya berkomentar
  • Ramah pencarian
    • semua kode sumber pihak pertama ada di appdirektori sehingga Anda dapat cdmenjalankan run / grep / xargs / ag / ack / etc dan tidak terganggu oleh pertandingan pihak ketiga
  • Gunakan penamaan yang sederhana dan jelas
    • npm sekarang tampaknya membutuhkan semua nama paket huruf kecil. Saya menemukan ini sebagian besar mengerikan tetapi saya harus mengikuti kawanan, sehingga nama file harus menggunakan kebab-casemeskipun nama variabel untuk itu dalam JavaScript harus camelCasekarena -merupakan tanda minus dalam JavaScript.
    • nama variabel cocok dengan nama path modul, tetapi dengan kebab-caseditransformasikan menjadicamelCase
  • Kelompokkan dengan Kopling, Bukan berdasarkan Fungsi
    • Ini adalah keberangkatan utama dari Ruby on Rails konvensi app/views, app/controllers, app/models, dll
    • Fitur ditambahkan ke tumpukan penuh, jadi saya ingin fokus pada setumpuk penuh file yang relevan dengan fitur saya. Ketika saya menambahkan bidang nomor telepon ke model pengguna, saya tidak peduli tentang pengontrol selain pengontrol pengguna, dan saya tidak peduli tentang model apa pun selain model pengguna.
    • Jadi, alih-alih mengedit 6 file yang masing-masing di direktori mereka sendiri dan mengabaikan banyak file lain di direktori tersebut, repositori ini diatur sedemikian rupa sehingga semua file yang saya butuhkan untuk membangun fitur dilokasi
    • Berdasarkan sifat MVC, tampilan pengguna digabungkan ke pengontrol pengguna yang digabungkan ke model pengguna. Jadi ketika saya mengubah model pengguna, 3 file tersebut akan sering berubah bersama, tetapi pengontrol penawaran atau pengontrol pelanggan dipisahkan dan dengan demikian tidak terlibat. Hal yang sama berlaku untuk desain non-MVC biasanya juga.
    • Gaya decoupling MVC atau MOVE dalam hal kode mana di mana modul masih didorong, tetapi menyebarkan file MVC ke direktori saudara hanya menjengkelkan.
    • Jadi masing-masing file rute saya memiliki bagian dari rute yang dimilikinya. routes.rbFile gaya rel berguna jika Anda menginginkan ikhtisar semua rute di aplikasi, tetapi ketika benar-benar membangun fitur dan memperbaiki bug, Anda hanya peduli dengan rute yang relevan dengan bagian yang Anda ubah.
  • Simpan tes di sebelah kode
    • Ini hanya contoh dari "grup dengan kopling", tapi saya ingin menyebutnya secara khusus. Saya telah menulis banyak proyek di mana tes hidup di bawah sistem file paralel yang disebut "tes" dan sekarang saya sudah mulai meletakkan tes saya di direktori yang sama dengan kode yang sesuai, saya tidak akan pernah kembali. Ini lebih modular dan lebih mudah untuk dikerjakan dengan editor teks dan mengurangi banyak jalan "../../ .." omong kosong. Jika Anda ragu, coba di beberapa proyek dan putuskan sendiri. Saya tidak akan melakukan apa pun di luar ini untuk meyakinkan Anda bahwa itu lebih baik.
  • Kurangi sambungan silang dengan Acara
    • Sangat mudah untuk berpikir "OK, setiap kali Kesepakatan baru dibuat, saya ingin mengirim email ke semua Tenaga Penjualan", dan kemudian hanya meletakkan kode untuk mengirim email itu di rute yang membuat kesepakatan.
    • Namun, kopling ini pada akhirnya akan mengubah aplikasi Anda menjadi bola lumpur raksasa.
    • Alih-alih, DealModel seharusnya hanya menjalankan acara "buat" dan sama sekali tidak mengetahui apa lagi yang mungkin dilakukan sistem dalam menanggapi hal itu.
    • Ketika Anda membuat kode dengan cara ini, akan jauh lebih mungkin untuk memasukkan semua kode terkait pengguna ke dalam app/userskarena tidak ada sarang tikus dari logika bisnis ditambah di semua tempat yang mencemari kemurnian basis kode pengguna.
  • Aliran kode bisa diikuti
    • Jangan lakukan hal-hal ajaib. Jangan memuat file secara otomatis dari direktori ajaib di sistem file. Jangan menjadi rel. Aplikasi dimulai app/server.js:1dan Anda dapat melihat semua yang dimuat dan dijalankan dengan mengikuti kode.
    • Jangan membuat DSL untuk rute Anda. Jangan melakukan metaprogram konyol ketika tidak dipanggil.
    • Jika aplikasi Anda begitu besar bahwa melakukan magicRESTRouter.route(somecontroller, {except: 'POST'})adalah kemenangan besar bagi Anda lebih dari 3 dasar app.get, app.put, app.del, panggilan, Anda mungkin membangun aplikasi monolitik yang terlalu besar untuk secara efektif bekerja pada. Dapatkan mewah untuk kemenangan BESAR, bukan untuk mengonversi 3 baris sederhana menjadi 1 baris kompleks.
  • Gunakan nama file huruf kecil kebab

    • Format ini menghindari masalah sensitivitas case sistem file di seluruh platform
    • npm melarang huruf besar dalam nama paket baru, dan ini berfungsi baik dengan itu

      spesifik express.js

  • Jangan gunakan app.configure. Ini hampir seluruhnya tidak berguna dan Anda hanya tidak membutuhkannya. Ada banyak boilerplate karena copypasta yang tidak ada artinya.

  • PESANAN MIDDLEWARE DAN ROUTES DALAM MASALAH EXPRESS !!!
    • Hampir setiap masalah routing yang saya lihat di stackoverflow adalah middleware ekspres yang tidak sesuai pesanan
    • Secara umum, Anda ingin rute Anda dipisahkan dan tidak terlalu bergantung pada pesanan
    • Jangan gunakan app.useuntuk seluruh aplikasi Anda jika Anda benar-benar hanya membutuhkan middleware untuk 2 rute (Saya melihat Anda, body-parser)
    • Pastikan ketika semua dikatakan dan dilakukan, Anda memiliki PERSIS pesanan ini:
      1. Semua middleware aplikasi super penting
      2. Semua rute Anda dan berbagai rute middlewares
      3. MAKA penangan kesalahan
  • Sayangnya, karena terinspirasi oleh sinatra, express.js sebagian besar mengasumsikan semua rute Anda akan berada server.jsdan akan jelas bagaimana mereka dipesan. Untuk aplikasi berukuran sedang, membagi hal-hal ke dalam modul rute terpisah itu bagus, tetapi hal itu memperkenalkan bahaya middleware rusak

Trik symlink aplikasi

Ada banyak pendekatan yang diuraikan dan dibahas panjang lebar oleh masyarakat dalam inti besar baik lokal memerlukan () jalur untuk Node.js . Saya mungkin segera memutuskan untuk memilih "hanya berurusan dengan banyak ../../../ .." atau menggunakan memerlukan dari mode. Namun, saat ini, saya telah menggunakan trik symlink yang dirinci di bawah ini.

Jadi salah satu cara untuk menghindari kebutuhan dalam proyek dengan jalur relatif yang mengganggu seperti require("../../../config")adalah dengan menggunakan trik berikut:

  • buat symlink di bawah node_modules untuk aplikasi Anda
    • cd node_modules && ln -nsf ../app
  • tambahkan saja node_modules / app symlink itu sendiri , bukan seluruh folder node_modules, ke git
    • git tambahkan -f node_modules / app
    • Ya, Anda masih harus memiliki "node_modules" di .gitignorefile Anda
    • Tidak, Anda tidak harus memasukkan "node_modules" ke repositori git Anda. Beberapa orang akan merekomendasikan Anda melakukan ini. Mereka salah.
  • Sekarang Anda dapat memerlukan modul intra-proyek menggunakan awalan ini
    • var config = require("app/config");
    • var DealModel = require("app/deals/deal-model");
  • Pada dasarnya, ini membuat intra-proyek membutuhkan kerja yang sangat mirip dengan yang dibutuhkan untuk modul npm eksternal.
  • Maaf, pengguna Windows, Anda harus tetap menggunakan jalur relatif direktori induk.

Konfigurasi

Umumnya kode modul dan kelas untuk mengharapkan hanya optionsobjek JavaScript dasar yang diteruskan. Hanya app/server.jsharus memuat app/config.jsmodul. Dari sana dapat mensintesis optionsobjek kecil untuk mengkonfigurasi subsistem yang diperlukan, tetapi menyambungkan setiap subsistem ke modul konfigurasi global besar yang penuh dengan informasi tambahan adalah kopling yang buruk.

Cobalah untuk memusatkan pembuatan koneksi DB dan mengirimkannya ke dalam subsistem yang bertentangan dengan melewati parameter koneksi dan membuat subsistem membuat koneksi keluar sendiri.

NODE_ENV

Ini adalah ide lain yang menarik tetapi mengerikan yang dibawa dari Rails. Seharusnya ada 1 tempat di aplikasi Anda, app/config.jsyang terlihat pada NODE_ENVvariabel lingkungan. Segala sesuatu yang lain harus mengambil opsi eksplisit sebagai argumen konstruktor kelas atau parameter konfigurasi modul.

Jika modul email memiliki opsi tentang cara mengirim email (SMTP, masuk ke stdout, masukkan antrian, dll), ia harus mengambil opsi seperti {deliver: 'stdout'}tetapi sama sekali tidak perlu memeriksa NODE_ENV.

Tes

Sekarang saya menyimpan file pengujian saya di direktori yang sama dengan kode yang sesuai dan menggunakan konvensi penamaan ekstensi nama file untuk membedakan tes dari kode produksi.

  • foo.js memiliki kode "foo" modul
  • foo.tape.js memiliki tes berbasis simpul untuk foo dan tinggal di dir yang sama
  • foo.btape.js dapat digunakan untuk tes yang perlu dijalankan di lingkungan browser

Saya menggunakan gumpalan filesystem dan find . -name '*.tape.js'perintah untuk mendapatkan akses ke semua pengujian saya sebagaimana diperlukan.

Cara mengatur kode dalam setiap .jsfile modul

Cakupan proyek ini kebanyakan tentang ke mana file dan direktori pergi, dan saya tidak ingin menambahkan banyak ruang lingkup lain, tetapi saya hanya akan menyebutkan bahwa saya mengatur kode saya menjadi 3 bagian yang berbeda.

  1. Membuka blok CommonJS membutuhkan panggilan ke dependensi negara
  2. Blok kode utama murni-JavaScript. Tidak ada polusi CommonJS di sini. Jangan merujuk ekspor, modul, atau mengharuskan.
  3. Blok penutup CommonJS untuk mengatur ekspor

1
Apa yang harus saya gunakan daripada bodyParser Jika saya hanya memiliki beberapa rute yang menggunakannya?
Ilan Frumer

3
Saya menemukan apa yang saya cari di sini: stackoverflow.com/questions/12418372/…
Ilan Frumer

1
@wlingke lihat gist.github.com/branneman/8048520 untuk diskusi menyeluruh tentang pendekatan yang tersedia untuk masalah itu.
Peter Lyons

@peterLyons Terima kasih telah membagikannya. Setelah membaca, saya pikir saya akan menulis skrip startup. Terima kasih!
wlingke

2
berkaitan dengan trik symlink aplikasi , ada modul kecil ini yang membuat semua masalah hilang
Hayko Koryun

157

UPDATE (2013-10-29) : Silakan lihat jawaban saya yang lain yang memiliki JavaScript alih-alih CoffeeScript berdasarkan permintaan populer serta repo boilerplate github dan README luas yang merinci rekomendasi terbaru saya tentang topik ini.

Konfigurasi

Apa yang Anda lakukan baik-baik saja. Saya ingin mengatur namespace konfigurasi saya sendiri di config.coffeefile tingkat atas dengan namespace bersarang seperti ini.

#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}"

Ini ramah untuk pengeditan sysadmin. Lalu ketika saya membutuhkan sesuatu, seperti info koneksi DB, itu `s

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

Rute / Pengendali

Saya suka meninggalkan rute saya dengan pengontrol saya dan mengaturnya dalam sebuah app/controllers subdirektori. Lalu saya dapat memuatnya dan membiarkan mereka menambahkan rute apa pun yang mereka butuhkan.

Dalam app/server.coffeefile kopi saya, saya lakukan:

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

Jadi saya punya file seperti:

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

Dan misalnya di pengontrol domain saya, saya memiliki setupfungsi seperti ini.

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

Tampilan

Menempatkan pandangan di app/viewsmenjadi tempat adat. Saya paparkan seperti ini.

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

File Statis

Masuk a public subdirektori.

Github / Semver / NPM

Letakkan file markdown README.md di root git repo Anda untuk github.

Letakkan file package.json dengan nomor versi semantik di root git repo Anda untuk NPM.


1
Hai Peter! Saya sangat menyukai pendekatan yang Anda pilih. Saya sedang mengerjakan membangun proyek ekspres dan saya benar-benar ingin melakukan hal-hal dengan cara yang benar daripada hanya untuk meretas dan meletakkannya di sekitar. Akan luar biasa jika Anda memiliki sampel repo di github dan / atau posting blog di atasnya.
suVasH .....

4
Repo ini memiliki banyak pola yang dapat Anda gunakan sebagai referensi: github.com/focusaurus/peterlyons.com
Peter Lyons

75
Skrip kopi membuat ini sulit dibaca: / Apakah ada kesempatan untuk mendapatkan suntingan vanilla JS? Terima kasih
toasted_flakes

1
Terima kasih atas jawaban ini. Saya hanya mencoba membungkus pikiran saya di sekitarnya. Bagaimana Anda mengakses pengontrol lain di dalam yang lain (mis. Dalam fungsi pengaturan seperti di atasapp.put route, api.needId
chmanie

@PeterLyons: hai manusia, saya memang melihat kode sumber Anda tetapi tidak tahu bagaimana cara membangun mode, saya sudah menginstal Godan memasukkan binfile ke dalam struktur. Bagaimana Anda menjalankan gofile itu bin?
user2002495

51

Berikut ini adalah jawaban Peter Lyons kata demi kata, dipindahkan ke vanilla JS dari Coffeescript, seperti yang diminta oleh beberapa orang lain. Jawaban Peter sangat bisa, dan siapa pun yang memilih jawaban saya harus memilihnya juga.


Konfigurasi

Apa yang Anda lakukan baik-baik saja. Saya ingin mengatur namespace konfigurasi saya sendiri di config.jsfile tingkat atas dengan namespace bersarang seperti ini.

// 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}"
};

Ini ramah untuk pengeditan sysadmin. Lalu ketika saya membutuhkan sesuatu, seperti info koneksi DB, itu `s

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

Rute / Pengendali

Saya suka meninggalkan rute saya dengan pengontrol dan mengaturnya dalamapp/controllers subdirektori. Lalu saya dapat memuatnya dan membiarkan mereka menambahkan rute apa pun yang mereka butuhkan.

Dalam app/server.jsfile javascript saya, saya lakukan:

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

Jadi saya punya file seperti:

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

Dan misalnya di pengontrol domain saya, saya memiliki setupfungsi seperti ini.

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

Tampilan

Menempatkan pandangan di app/viewsmenjadi tempat adat. Saya paparkan seperti ini.

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

File Statis

Bukapublic subdirektori.

Github / Semver / NPM

Letakkan file markdown README.md di root git repo Anda untuk github.

Letakkan file package.json dengan nomor versi semantik di root git repo Anda untuk NPM.


43

Pertanyaan saya diperkenalkan pada bulan April 2011, sudah tua tenang. Selama ini, saya bisa meningkatkan pengalaman saya dengan Express.js dan bagaimana membuat arsitektur aplikasi yang ditulis menggunakan perpustakaan ini. Jadi, saya berbagi pengalaman saya di sini.

Inilah struktur direktori saya:

├── 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

Tujuan dari app.jsfile ini adalah untuk mem-bootstrap aplikasi expressjs. Itu memuat modul konfigurasi, modul logger, menunggu koneksi database, ..., dan menjalankan server ekspres.

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

rute /

Direktori rute memiliki index.jsfile. Tujuannya adalah untuk memperkenalkan semacam sihir untuk memuat semua file lain di dalam routes/direktori. Inilah implementasinya:

/**
 * 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);
  });
};

Dengan modul itu, membuat definisi rute baru dan implementasi sangat mudah. Untuk contoh, hello.js:

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

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

Setiap modul rute adalah mandiri .


Apakah Anda menggunakan generator untuk membuat struktur ini?
Ashish


17

Saya pikir ini cara yang bagus untuk melakukannya. Tidak terbatas untuk mengekspresikan tetapi saya telah melihat cukup banyak proyek node.js di github melakukan hal yang sama. Mereka mengeluarkan parameter konfigurasi + modul yang lebih kecil (dalam beberapa kasus setiap URI) diperhitungkan dalam file terpisah.

Saya akan merekomendasikan melalui proyek kilat khusus pada github untuk mendapatkan ide. IMO seperti yang Anda lakukan benar.


16

sekarang adalah Akhir 2015 dan setelah mengembangkan struktur saya selama 3 tahun dan dalam proyek-proyek kecil dan besar. Kesimpulan?

Jangan melakukan satu MVC besar, tetapi pisahkan dalam modul

Begitu...

Mengapa?

  • Biasanya satu bekerja pada satu modul (misalnya Produk), yang dapat Anda ubah secara independen.

  • Anda dapat menggunakan kembali modul

  • Anda dapat mengujinya secara terpisah

  • Anda dapat menggantinya secara terpisah

  • Mereka memiliki antarmuka yang jelas (stabil)

    -Pada terbaru, jika ada beberapa pengembang bekerja, pemisahan modul membantu

Proyek nodebootstrap memiliki pendekatan yang mirip dengan struktur akhir saya. ( github )

Bagaimana struktur ini terlihat?

  1. Modul-modul kecil yang diberi kapsul , masing-masing dengan MVC yang terpisah

  2. Setiap modul memiliki package.json

  3. Pengujian sebagai bagian dari struktur (dalam setiap modul)

  4. Konfigurasi global , perpustakaan, dan Layanan

  5. Docker Terintegrasi, Cluster, selamanya

Folderoverview (lihat folder lib untuk modul):

struktur nodebootstrap


3
Akan sangat membantu jika Anda dapat memperbarui gambar ikhtisar folder dengan masing-masing modul diperluas, sebagai contoh bagaimana Anda akan menyusunnya juga.
youngrrrr

8

Saya memberikan struktur folder gaya MVC, silakan temukan di bawah.

Kami menggunakan struktur folder di bawah ini untuk aplikasi web besar dan sedang kami.

 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

Saya telah membuat satu modul npm untuk pembuatan folder folder mvc express.

Silakan temukan di bawah https://www.npmjs.com/package/express-mvc-generator

Hanya langkah-langkah sederhana untuk menghasilkan dan menggunakan modul ini.

i) memasang modul npm install express-mvc-generator -g

ii) periksa opsi express -h

iii) Hasilkan struktur mvc ekspres express myapp

iv) Instal dependensi: npm install ::

v) Buka config / database.js Anda, Konfigurasikan mongo db Anda.

vi) Jalankan aplikasi node appataunodemon app

vii) Periksa URL http: // localhost: 8042 / daftar ATAU http: // yourip: 8042 / daftar


7

Sudah cukup lama sejak jawaban terakhir untuk pertanyaan ini dan Express juga baru-baru ini merilis versi 4, yang menambahkan beberapa hal berguna untuk mengatur struktur aplikasi Anda.

Di bawah ini adalah posting blog yang panjang dan terkini tentang praktik terbaik tentang cara menyusun aplikasi Express Anda. http://www.terlici.com/2014/08/25/best-practices-express-structure.html

Ada juga repositori GitHub yang menerapkan saran dalam artikel. Selalu up to date dengan versi Express terbaru.
https://github.com/terlici/base-express


7

Saya tidak berpikir itu pendekatan yang baik untuk menambahkan rute ke konfigurasi. Struktur yang lebih baik bisa seperti ini:

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...

Jadi products.js dan users.js akan berisi semua rute Anda akan semua logika di dalamnya.


6

Yah saya meletakkan rute saya sebagai file json, yang saya baca di awal, dan dalam for-loop di app.js mengatur rute. Route.json termasuk tampilan mana yang harus dipanggil, dan kunci untuk nilai-nilai yang akan dikirim ke rute.
Ini berfungsi untuk banyak kasus sederhana, tetapi saya harus secara manual membuat beberapa rute untuk kasus khusus.


6

Saya telah menulis posting tentang hal ini. Ini pada dasarnya menggunakan routeRegistrarfile yang di-iterates melalui folder yang /controllersmemanggil fungsinya init. Function initmengambil appvariabel express sebagai parameter sehingga Anda bisa mendaftarkan rute Anda seperti yang Anda inginkan.

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) Sistem file proyek Express Anda mungkin seperti:

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

app.js - Anda wadah aplikasi global

2) File utama modul (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) Hubungkan modul di app.js utama

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

4) Contoh logika

lib/login
lib/db
lib/config
lib/users
lib/verify
lib/
   /api/ 
   ...
lib/
   /admin/
      /users/
      /settings/
      /groups/
...
  • Terbaik untuk pengujian
  • Terbaik untuk skala
  • Terpisah tergantung pada modul
  • Mengelompokkan rute berdasarkan fungsionalitas (atau modul)

tj mengatakan / tunjukkan pada Vimeo ide menarik bagaimana memodulasi aplikasi ekspres - aplikasi web modular dengan Node.js dan Express . Kuat dan sederhana.


4

http://locomotivejs.org/ menyediakan cara untuk menyusun aplikasi yang dibangun dengan Node.js dan Express.

Dari situs web:

"Lokomotif adalah kerangka kerja web untuk Node.js. Lokomotif mendukung pola MVC, rute yang tenang, dan konvensi atas konfigurasi, sambil berintegrasi dengan mulus dengan mesin database dan template apa pun. Lokomotif dibuat berdasarkan Express, menjaga daya dan kesederhanaan yang Anda harapkan. dari Node. "


3

Saya baru-baru memeluk modul sebagai mini-aplikasi independen.

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

Sekarang untuk setiap perutean modul (# .js), pandangan (* .ejs), js, css dan aset bersebelahan. perutean submodule diatur di induk # .js dengan dua baris tambahan

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

Dengan cara ini, bahkan sub-modul mungkin.

Jangan lupa untuk mengatur tampilan ke direktori src

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

setiap tautan ke github dengan struktur seperti itu tertarik untuk melihat bagaimana rute, tampilan, dan model dimuat
Muhammad Umer

Saya pikir semuanya sudah dijelaskan. Rute hanyalah rute ekspres klasik. Tampilan harus dimuat diawali dengan nama modul, model harus dimuat dengan mereferensikan jalur relatif.
zevero

Pada baris terakhir saya, saya mengatur tampilan ke direktori src. Jadi mulai sekarang, semua tampilan dapat diakses relatif ke direktori src. Tidak ada yang mewah.
zevero

1

Ini adalah bagaimana sebagian besar struktur direktori proyek kilat saya terlihat.

Saya biasanya melakukan express dirnameuntuk menginisialisasi proyek, maafkan kemalasan saya, tetapi sangat fleksibel dan dapat diperpanjang. PS - Anda perlu mendapatkannya express-generator(untuk mereka yang mencarinya sudo npm install -g express-generator, sudo karena Anda menginstalnya secara global)

|-- 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

Anda pasti bertanya-tanya mengapa file .env? Karena mereka bekerja! Saya menggunakan dotenvmodul dalam proyek saya (baru-baru ini) dan berfungsi! Masukkan 2 pernyataan ini di app.jsatauwww

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

Dan baris lain untuk mengatur dengan cepat /bower_componentsuntuk menyajikan konten statis di bawah sumber daya/ext

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

Mungkin bisa cocok untuk orang yang ingin menggunakan Express dan Angular bersama, atau hanya mengekspresikan tanpa javascriptshierarki itu tentu saja.


1

Struktur saya ekspres 4. https://github.com/odirleiborgert/borgert-express-boilerplate

Paket

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

Struktur

|-- 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

Cara sederhana untuk menyusun aplikasi Anda:

  • Di index.js utama, urutan berikut harus dipertahankan.

    semua app.set harus menjadi yang pertama.

    semua app.use harus menjadi yang kedua.

    diikuti oleh apis lain dengan fungsi atau rute-lanjutkan di file lain

    Exapmle

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

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

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

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


0

Cara Terbaik Menuju Struktur MVC untuk Proyek ExpressJs dengan stang & Paspor

- 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 silakan periksa
Manishkumar Bhavnani
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.