วิธีการทำให้ node.js ต้องการค่าสัมบูรณ์ (แทนญาติ)


234

ฉันต้องการเรียกใช้ไฟล์ของฉันเสมอตามรูทของโครงการและไม่สัมพันธ์กับโมดูลปัจจุบัน

ตัวอย่างเช่นหากคุณดูที่https://github.com/visionmedia/express/blob/2820f2227de0229c5d7f28009aa432f9f3a7b5f9/examples/downloads/app.jsบรรทัดที่ 6 คุณจะเห็น

express = require('../../')

นั่นเป็น IMO ที่แย่จริงๆ ลองนึกภาพฉันอยากจะยกตัวอย่างทั้งหมดของฉันให้ใกล้กับรูทมากขึ้นเพียงระดับเดียว นั่นคงเป็นไปไม่ได้เพราะฉันจะต้องอัปเดตตัวอย่างมากกว่า 30 รายการและหลายครั้งในแต่ละตัวอย่าง สำหรับสิ่งนี้:

express = require('../')

วิธีแก้ปัญหาของฉันคือมีกรณีพิเศษสำหรับรูทตาม: หากสตริงเริ่มต้นด้วย $ ดังนั้นมันจะสัมพันธ์กับโฟลเดอร์รูทของโครงการ

ความช่วยเหลือใด ๆ ที่ชื่นชมขอบคุณ

อัปเดต 2

ตอนนี้ฉันใช้ require.js ซึ่งช่วยให้คุณสามารถเขียนได้ในทิศทางเดียวและทำงานได้ทั้งบนไคลเอนต์และบนเซิร์ฟเวอร์ Require.js ยังอนุญาตให้คุณสร้างเส้นทางที่กำหนดเอง

อัปเดต 3

ตอนนี้ฉันย้ายไปที่ webpack + gulp และฉันต้องการขั้นสูงเพื่อจัดการกับโมดูลที่ฝั่งเซิร์ฟเวอร์ ดูที่นี่เหตุผล: http://hackhat.com/p/110/module-loader-webpack-vs-requirejs-vs-browserify/


หากคุณเคยตัดสินใจที่จะใช้ค่าคงที่ / ตัวแปรของรูทพา ธ ที่ชัดเจนคำตอบนี้ใช้ได้สำหรับสิ่งนั้น วิธีการแก้ปัญหาใช้โมดูล Github เล็ก ๆ เพื่อกำหนดเส้นทางของรูท
steampowered

คำตอบ:


162

และสิ่งที่เกี่ยวกับ:

var myModule = require.main.require('./path/to/module');

มันต้องใช้ไฟล์ราวกับว่ามันต้องการจากไฟล์ js หลักดังนั้นมันจึงทำงานได้ดีตราบใดที่ไฟล์ js หลักของคุณอยู่ที่รากของโครงการของคุณ ... และนั่นคือสิ่งที่ฉันขอขอบคุณ


ไม่ใช่ความคิดที่ไม่ดี (: จากนั้นคุณสามารถกำหนดวิธีการอื่นเพื่อทำการแมปแอปใหม่ในโมดูล require.main ของคุณฉันคิดว่าคุณสามารถทำได้ require.main.req ('ไคลเอนต์ / someMod') ความคิดที่ดี แต่สิ่งนี้จะ ละเอียดกว่าที่ฉันต้องการในปัจจุบันฉันไม่คิดว่ามันคุ้มค่าเพราะฉันไม่ชอบ browserify เพราะการเปลี่ยนแปลงไม่ได้เกิดขึ้นทันทีและพลาดการเปลี่ยนแปลง (เพราะรหัสของฉันควรทำงานทั้งในเบราว์เซอร์และ node.js)
Totty.js

4
หากคุณพบว่า verbose เกินไปให้ใช้. ผูก (): var rootReq = require.bind (require.main); rootReq ('./path/to/module');
cronvel

ใช่สิ่งนี้มีประโยชน์สำหรับคนที่ยังต้องการใช้ browserify สำหรับฝั่งไคลเอ็นต์ สำหรับฉันไม่มีความจำเป็นอีกต่อไป แต่ขอบคุณสำหรับคำตอบของคุณ (:
Totty.js

6
ถ้าหลักอยู่ที่รูทของโครงการของคุณ :)
Alexander Mills

12
วิธีนี้จะไม่ทำงานหากรหัสที่ครอบคลุมกับการทดสอบหน่วยเช่น Mocha test
alx lark

129

มีส่วนที่น่าสนใจจริงๆในคู่มือ Browserify :

หลีกเลี่ยง ../../../../../../ ..

ไม่ใช่ทุกสิ่งในแอปพลิเคชันที่เหมาะสมเป็นของสาธารณะ npm และค่าใช้จ่ายในการตั้งค่า npm ส่วนตัวหรือ git repo ยังคงค่อนข้างใหญ่ในหลายกรณี ต่อไปนี้เป็นวิธีการบางส่วนในการหลีกเลี่ยง ../../../../../../../ปัญหาเส้นทางสัมพัทธ์

node_modules

บางครั้งผู้คนคัดค้านการวางโมดูลเฉพาะแอปพลิเคชันลงใน node_modules เนื่องจากไม่ชัดเจนว่าจะตรวจสอบโมดูลภายในของคุณอย่างไรโดยไม่ตรวจสอบในโมดูลบุคคลที่สามจาก npm

คำตอบนั้นง่ายมาก! หากคุณมี.gitignoreไฟล์ที่ละเว้นnode_modules:

node_modules

คุณสามารถเพิ่มข้อยกเว้น!สำหรับแต่ละโมดูลแอปพลิเคชันภายในของคุณ:

node_modules/*
!node_modules/foo
!node_modules/bar

โปรดทราบว่าคุณไม่สามารถยกเลิกการลงทะเบียนไดเรกทอรีย่อยหากผู้ปกครองถูกเพิกเฉยแล้ว ดังนั้นแทนที่จะเพิกเฉยnode_modulesคุณต้องเพิกเฉยทุก ๆ ไดเรกทอรีที่อยู่ภายใน node_modulesด้วย node_modules/*เคล็ดลับแล้วคุณสามารถเพิ่มข้อยกเว้นของคุณ

ตอนนี้ทุกที่ในแอปพลิเคชันของคุณคุณจะสามารถrequire('foo') หรือrequire('bar')ไม่มีเส้นทางญาติที่ใหญ่และบอบบาง

หากคุณมีโมดูลจำนวนมากและต้องการแยกโมดูลเหล่านี้ออกจากโมดูลของบุคคลที่สามที่ติดตั้งโดย npm คุณสามารถวางโมดูลเหล่านั้นไว้ในไดเรกทอรีnode_modulesเช่นnode_modules/app:

node_modules/app/foo
node_modules/app/bar

ตอนนี้คุณจะสามารถrequire('app/foo')หรือrequire('app/bar') จากที่ใดก็ได้ในแอปพลิเคชันของคุณ

ในของคุณ.gitignoreเพียงเพิ่มข้อยกเว้นสำหรับnode_modules/app:

node_modules/*
!node_modules/app

หากแอปพลิเคชันของคุณมีการแปลงการกำหนดค่าใน package.json คุณจะต้องสร้าง package.json แยกต่างหากด้วยฟิลด์การแปลงของตัวเองในไดเรกทอรีส่วนประกอบของคุณnode_modules/fooหรือnode_modules/app/fooเนื่องจากการแปลงไม่ได้ใช้ข้ามขอบเขตของโมดูล สิ่งนี้จะทำให้โมดูลของคุณแข็งแกร่งขึ้นเมื่อเทียบกับการเปลี่ยนแปลงการกำหนดค่าในแอปพลิเคชันของคุณและมันจะง่ายกว่าที่จะนำแพคเกจภายนอกมาใช้อย่างอิสระ

symlink

เคล็ดลับที่มีประโยชน์อีกอย่างถ้าคุณกำลังทำงานกับแอปพลิเคชันที่คุณสามารถสร้าง symlink และไม่จำเป็นต้องสนับสนุน windows ก็คือการเชื่อมโยง a lib/ หรือapp/โฟลเดอร์เข้าnode_modulesด้วยกัน จากรูทโปรเจ็กต์ให้ทำ:

ln -s ../lib node_modules/app

และตอนนี้จากที่ใดก็ได้ในโครงการของคุณคุณจะต้องใช้ไฟล์ในlib/การดำเนินการrequire('app/foo.js')เพื่อให้ได้lib/foo.jsมา

เส้นทางที่กำหนดเอง

คุณอาจเห็นสถานที่บางแห่งพูดถึงการใช้$NODE_PATH ตัวแปรสภาพแวดล้อมหรือopts.pathsเพิ่มไดเรกทอรีสำหรับโหนดและเบราว์เซอร์เพื่อค้นหาโมดูล

ไม่เหมือนกับแพลตฟอร์มอื่น ๆ ส่วนใหญ่การใช้อาร์เรย์สไตล์เชลล์ของไดเรกทอรีพา ธ ด้วย$NODE_PATHไม่ดีเท่าในโหนดเมื่อเทียบกับการใช้node_modulesไดเรกทอรีอย่างมีประสิทธิภาพ

นี่เป็นเพราะแอปพลิเคชันของคุณเชื่อมต่ออย่างแน่นหนากับการกำหนดค่าสภาพแวดล้อมรันไทม์มากขึ้นดังนั้นจึงมีชิ้นส่วนที่เคลื่อนไหวได้มากขึ้นและแอปพลิเคชันของคุณจะทำงานเฉพาะเมื่อสภาพแวดล้อมการตั้งค่าถูกต้อง

โหนดและ browserify สนับสนุนทั้งสอง $NODE_PATHแต่กีดกันการใช้งานของ


17
ข้อเสียเพียงอย่างเดียวของการวางลงในnode_modulesโฟลเดอร์คือมันทำให้rm -rf node_modulesโฟลเดอร์nuke ( ) ยากยิ่งขึ้น
Michael

13
@Michael ไม่ยากมาก: git clean -dx node_modules
Peter Wilkinson

3
หรือในกรณีที่คุณลืมgit cleanไวยากรณ์สิ่งใดสิ่งหนึ่งสามารถทำได้ตลอดเวลาrm -rf node_modules && git checkout node_modules- ให้แน่ใจว่าgit stashในกรณีที่มีการเปลี่ยนแปลงใด ๆ ในnode_modulesไดเรกทอรีย่อย
derenio

1
ฉันชอบความคิดในการใช้ node_modules แต่ไม่ใช่สำหรับการจัดเก็บซอร์สโค้ดเนื่องจากพิจารณาว่ามันจะระเหยได้อย่างไร มันจะไม่เหมาะสมกว่าที่จะเผยแพร่โมดูลแยกและบันทึกเป็นอ้างอิงในโครงการต้นฉบับหรือไม่ เป็นโซลูชันที่ชัดเจนสำหรับความผันผวนของไดเร็กทอรี node_modules และอาศัยเพียง npm แทนที่จะพึ่งพา git ลิงก์สัญลักษณ์หรือโซลูชัน $ NODE_PATH
Kevin Koshiol

1
NODE_PATH ดูเหมือนว่าจะไป "แอปพลิเคชันของคุณจะทำงานเมื่อตั้งค่าสภาพแวดล้อมของคุณถูกต้อง" นี่เป็นความจริงเสมอ! การตั้งค่าสภาพแวดล้อม (ปกติเป็นหนึ่งไฟล์) นั้นง่ายกว่าการเปลี่ยนการนำเข้าทุกครั้งในทุกไฟล์หรือไม่?
CpILL

73

ฉันต้องการสร้างnode_modulesโฟลเดอร์ใหม่สำหรับรหัสที่ใช้ร่วมกันแล้วปล่อยให้โหนดและต้องการทำสิ่งที่ดีที่สุด

ตัวอย่างเช่น:

- node_modules // => these are loaded from your package.json
- app
  - node_modules // => add node-style modules
    - helper.js
  - models
    - user
    - car
- package.json
- .gitignore

ตัวอย่างเช่นหากคุณอยู่ในcar/index.jsคุณสามารถrequire('helper')และโหนดจะพบมัน!

node_modules ทำงานอย่างไร

โหนดมีอัลกอริทึมที่ชาญฉลาดสำหรับการแก้ไขโมดูลที่ไม่ซ้ำกันในหมู่แพลตฟอร์มคู่แข่ง

หากคุณrequire('./foo.js')จาก/beep/boop/bar.jsโหนดจะมองหาใน./foo.js /beep/boop/foo.jsเส้นทางที่เริ่มต้นด้วย./หรืออยู่เสมอในท้องถิ่นไปยังแฟ้มที่โทร../require()

หากคุณต้องการชื่อที่ไม่เกี่ยวข้องเช่นrequire('xyz')จาก/beep/boop/foo.jsโหนดจะค้นหาเส้นทางเหล่านี้ตามลำดับหยุดที่คู่แรกและเพิ่มข้อผิดพลาดหากไม่พบสิ่งใด

/beep/boop/node_modules/xyz
/beep/node_modules/xyz
/node_modules/xyz

สำหรับแต่ละxyzไดเร็กทอรีที่มีอยู่โหนดจะค้นหา a ก่อนxyz/package.jsonเพื่อดูว่ามี"main"ฟิลด์อยู่หรือไม่ "main"กำหนดฟิลด์ซึ่งไฟล์ควรใช้ค่าใช้จ่ายถ้าคุณrequire()เส้นทางไดเรกทอรี

ตัวอย่างเช่นหาก/beep/node_modules/xyzเป็นการแข่งขันนัดแรกและ/beep/node_modules/xyz/package.jsonมี:

{
  "name": "xyz",
  "version": "1.2.3",
  "main": "lib/abc.js"
}

แล้วส่งออกจากจะถูกส่งกลับโดย/beep/node_modules/xyz/lib/abc.js require('xyz')

หากไม่มีpackage.jsonหรือไม่มี"main"ฟิลด์index.jsจะถือว่า:

/beep/node_modules/xyz/index.js

2
คำอธิบายที่ดีเกี่ยวกับวิธีการทำงานเมื่อโหลดโมดูล
เริ่ม

2
นี่เป็นทางออกที่หรูหรามากหลีกเลี่ยงปัญหาทั้งหมดในคำตอบข้างต้น ควรพิจารณาคำตอบด้วยนะ
rodurico

38

ภาพใหญ่

ดูเหมือนว่า "ไม่ดีจริง ๆ " แต่ให้เวลา จริงๆแล้วมันดีจริงๆ สิ่งที่ชัดเจนนั้นrequire()ให้ความโปร่งใสและความเข้าใจที่ง่ายเหมือนกับการสูดอากาศบริสุทธิ์ในช่วงวงจรชีวิตของโครงการ

คิดแบบนี้: คุณกำลังอ่านตัวอย่างจุ่มนิ้วเท้าของคุณลงใน Node.js และคุณตัดสินใจว่าเป็น "IMO ที่ไม่ดีจริงๆ" คุณเป็นผู้นำที่คาดเดาได้เป็นครั้งที่สองของชุมชน Node.js ผู้ที่เข้าสู่ระบบการเขียนและบำรุงรักษาแอปพลิเคชัน Node.js มากกว่าชั่วโมง โอกาสที่ผู้เขียนทำผิดพลาดเช่นนี้คืออะไร? (และฉันเห็นด้วยจากพื้นหลัง Ruby และ Python ของฉันดูเหมือนว่าในตอนแรกจะเป็นหายนะ)

มี hype และ counter-hype มากมายรอบ ๆ Node.js แต่เมื่อฝุ่นตกลงเราจะยอมรับว่าโมดูลที่ชัดเจนและแพ็คเกจ "โลคอลแรก" นั้นเป็นตัวขับเคลื่อนหลักของการนำไปใช้

กรณีทั่วไป

แน่นอนnode_modulesจากไดเรกทอรีปัจจุบันจากนั้นผู้ปกครองแล้วปู่ย่าตายายที่ยิ่งใหญ่ปู่ย่าตายาย ฯลฯ มีการค้นหา ดังนั้นแพ็คเกจที่คุณติดตั้งจึงใช้งานได้แล้ว โดยปกติแล้วคุณสามารถทำได้require("express")ทุกที่ในโครงการของคุณและทำงานได้ดี

หากคุณพบว่าตัวเองกำลังโหลดไฟล์ทั่วไปจากรากของโครงการของคุณ (อาจเป็นเพราะพวกเขาเป็นฟังก์ชั่นยูทิลิตี้ทั่วไป) นั่นเป็นเบาะแสที่ยิ่งใหญ่ที่ถึงเวลาทำแพ็คเกจ แพคเกจนั้นง่ายมาก: ย้ายไฟล์ของคุณไปnode_modules/ไว้ที่package.json นั่น Voila! ทุกอย่างในเนมสเปซนั้นสามารถเข้าถึงได้จากโครงการทั้งหมดของคุณ แพคเกจเป็นวิธีที่ถูกต้องในการนำรหัสของคุณไปไว้ในเนมสเปซส่วนกลาง

วิธีแก้ไขอื่น ๆ

โดยส่วนตัวฉันไม่ได้ใช้เทคนิคเหล่านี้ แต่พวกเขาตอบคำถามของคุณและแน่นอนว่าคุณรู้สถานการณ์ของตัวเองดีกว่าฉัน

คุณสามารถตั้งค่า$NODE_PATHเป็นรูทโครงการของคุณ require()ไดเรกทอรีที่จะค้นหาเมื่อคุณ

ถัดไปคุณสามารถประนีประนอมและต้องการไฟล์ท้องถิ่นทั่วไปจากตัวอย่างทั้งหมดของคุณ ไฟล์ทั่วไปนั้นจะส่งออกไฟล์จริงอีกครั้งในไดเรกทอรี grandparent

ตัวอย่าง / ดาวน์โหลด / app.js (และอื่น ๆ อีกมากมายชอบมัน)

var express = require('./express')

ตัวอย่าง / ดาวน์โหลด / express.js

module.exports = require('../../')

ตอนนี้เมื่อคุณย้ายไฟล์เหล่านั้นกรณีที่แย่ที่สุดคือแก้ไขโมดูลshimหนึ่งโมดูล


14
ฉันยอมรับว่าพวก Node.js ต้องเลือกญาติต้องมีเหตุผล ฉันไม่เห็นข้อดีของมันเลยทั้งคำตอบของคุณ มันยังรู้สึกว่า "ไม่ดี" สำหรับฉัน;)
Adam Schmideg

21
“ คุณเป็นผู้นำที่คาดเดาได้เป็นครั้งที่สองของชุมชน Node.js” - ผู้นำกลุ่มเดียวกันจึงตัดสินใจใช้การโทรกลับแทนสัญญาซื้อขายล่วงหน้า ส่วนใหญ่ของการให้คำปรึกษา nodejs ของฉันเกี่ยวข้องกับการสาปแช่งกล่าวว่า "ผู้นำ" และโน้มน้าวให้คนที่จะย้ายไป JVM ซึ่งมีมากขึ้นหลังจากไม่กี่เดือนของการใช้ nodejs :)
เดวิด Sergey

8
@nirth ย้ายไปที่ JVM หรือไม่ เพื่อประโยชน์ของพระเจ้าทำไม?
Ivancho

31
"คุณเป็นผู้นำที่คาดเดาได้เป็นครั้งที่สองของชุมชน Node.js" โปรดหลีกเลี่ยงน้ำเสียงที่ทำให้ท้อใจ
atlex2

15
ประณามเขาเป็นผู้นำโหนดที่เดาได้เป็นครั้งที่สอง นั่นเป็นวิธีที่อุตสาหกรรมดำเนินไป หากพวกโหนดไม่ได้คาดเดาผู้นำที่โพสต์รูปแบบการทำงานพร้อมกันของเธรดเราจะไม่มีโหนด
d512

20

มีลักษณะที่โหนดฉิบหาย

มันง่ายอย่างนี้:

var rfr = require('rfr');
var myModule = rfr('projectSubDir/myModule');

ฉันคิดว่าบรรทัดที่สองควรเป็น var myModule = rfr ('/ projectSubDir / myModule');
Sikorski

1
จากเอกสาร: var module2 = rfr ('lib / module2'); // สแลชชั้นนำสามารถละเว้นได้
igelineau

ฉันลองแล้ว rfr ใช้งานได้ดีกับการทำงานกับโหนด แต่มันหยุดการนำทางโค้ดด้วย VS Code ... ฉันไม่สามารถหาวิธีแก้ปัญหาเพื่อให้สามารถใช้การเติมข้อความอัตโนมัติใน VS ...
Alex Mantaut

13

หากคุณใช้ไหมพรมแทนการใช้npmคุณสามารถใช้พื้นที่ทำงานได้

สมมติว่าฉันมีโฟลเดอร์ที่servicesฉันต้องการได้ง่ายขึ้น:

.
├── app.js
├── node_modules
├── test
├── services
   ├── foo
   └── bar
└── package.json

หากต้องการสร้างเวิร์กสเปซ Yarn ให้สร้างpackage.jsonไฟล์ภายในservices folder:

{
  "name": "myservices",
  "version": "1.0.0"
}

ในแพ็คเกจหลักของคุณเพิ่ม:

"private": true,
"workspaces": ["myservices"]

เรียกใช้yarn installจากรูทของโครงการ

จากนั้นในรหัสของคุณคุณสามารถทำได้:

const { myFunc } = require('myservices/foo')

แทนสิ่งที่ชอบ:

const { myFunc } = require('../../../../../../services/foo')

6
อาจเป็นความคิดที่จะชี้แจงว่าสิ่งนี้ใช้ได้กับเส้นด้ายเท่านั้นไม่ใช่สำหรับ npm ใช่ไหม ฉันคิดว่ามันน่าจะใช้ได้สำหรับ npm เช่นกันดังนั้นใช้เวลาสักครู่เพื่อสงสัยว่าฉันทำอะไรผิดจนกระทั่งฉันลองใช้ไหมพรมแทน อาจเป็นข้อสมมุติที่โง่เขลา แต่บางทีฉันอาจไม่ใช่คนเดียว
ArneHugo

2
ฉันได้แก้ไขเล็กน้อยเพื่อชี้แจง ขอโทษสำหรับความสับสน.
cyberwombat

12

IMHO วิธีที่ง่ายที่สุดคือกำหนดฟังก์ชันของคุณเองเป็นส่วนหนึ่งของGLOBALวัตถุ สร้างprojRequire.jsในรากของโครงการของคุณด้วยเนื้อหาต่อไปนี้:

var projectDir = __dirname;

module.exports = GLOBAL.projRequire = function(module) {
  return require(projectDir + module);
}

ในไฟล์หลักของคุณก่อนที่จะเข้าrequireร่วมโมดูลเฉพาะโครงการใด ๆ :

// init projRequire
require('./projRequire');

หลังจากนั้นใช้งานได้สำหรับฉัน:

// main file
projRequire('/lib/lol');

// index.js at projectDir/lib/lol/index.js
console.log('Ok');


@Totty ฉันได้พบกับโซลูชันอื่นซึ่งสามารถทำงานได้ในกรณีที่คุณอธิบายไว้ในความคิดเห็น รายละเอียดจะเป็นtl;drดังนั้นฉันดีกว่าแสดงภาพที่มีโครงสร้างของโครงการการทดสอบของฉัน


ดีจนถึงตอนนี้ดูเหมือนว่าวิธีที่ดีที่สุดที่จะทำ ฉันทำได้: GLOBAL.requires = require ('r') r; ในไฟล์ index.js ของฉัน แต่ฉันมีปัญหาในการทดสอบคำสาบานของพวกเขาพวกเขาไม่ได้เรียกใช้ index.js ดังนั้นการทดสอบของฉันล้มเหลวเพราะต้องการมันไม่ได้กำหนด อย่างไรก็ตามตอนนี้ฉันสามารถเพิ่ม GLOBAL.requires = require ('r') ได้ r; ที่ด้านบนของการทดสอบทุกครั้ง มีความคิดที่ดีกว่านี้ไหม? github.com/totty90/production01_server/commit/…
Totty.js

สำหรับไฟล์ทดสอบที่ไม่ใช่: github.com/totty90/production01_server/blob/global-require/… , ในไฟล์ทดสอบแต่ละไฟล์: github.com/totty90/production01_server/blob/global-require/test/…
Totty.js

ปัญหาเกิดขึ้นเมื่อฉันอยู่ใน "pathes-test / node_modules / other.js" และฉันต้องการ "pathes-test / node_modules / some.js" ฉันควรต้องการ ('./ some') แทนที่จะต้องการ ("prj / some") และด้วยวิธีนี้แอปทั้งหมดของฉันจะอยู่ใน node_modules dir?
Totty.js

@Totty ไม่ต้องมีปัญหาprj/someจากprj/other(เพิ่งทดสอบrequire('prj/some') โมดูลทั่วไปของแอปทั้งหมดของคุณสามารถไปที่นั่นได้ (เช่นเลเยอร์ฐานข้อมูล) จะไม่สร้างความแตกต่างในที่ที่คุณสมมุติว่าlibเป็น ลองดูว่าเหมาะสมหรือไม่
Aleksei Zabrodskii

ใช่ฉันได้อัปเดตแล้ว: github.com/totty90/production01_server/tree/master/node_modules/…ที่ใช้งานได้ดี แต่ฉันสามารถวางไฟล์ทั้งหมดของฉันให้อยู่ในระดับเดียวโดยไม่ต้องใช้ node_modules
Totty.js

12

ฉันใช้process.cwd()ในโครงการของฉัน ตัวอย่างเช่น:

var Foo = require(process.cwd() + '/common/foo.js');

มันอาจจะคุ้มค่าที่จะสังเกตว่าสิ่งนี้จะส่งผลให้เกิดrequireเส้นทางที่แน่นอนแม้ว่าฉันจะยังไม่พบปัญหาเกี่ยวกับสิ่งนี้


1
เป็นความคิดที่ไม่ดีเพราะ CWD ไม่จำเป็นต้องเป็นไดเรกทอรีเดียวกันกับที่บันทึกแอปพลิเคชัน
jiwopene

11

มีการอภิปรายที่ดีของปัญหานี้เป็นที่นี่

ฉันพบปัญหาสถาปัตยกรรมเดียวกัน: ต้องการวิธีเพิ่มแอปพลิเคชันของฉันให้กับองค์กรและเนมสเปซภายในเพิ่มเติมโดยไม่ต้อง:

  • การผสมโมดูลแอปพลิเคชันที่มีการอ้างอิงภายนอกหรือรบกวนกับ repos ส่วนตัวของ npm สำหรับรหัสเฉพาะแอปพลิเคชัน
  • ใช้ความต้องการญาติซึ่งทำให้ refactoring และเข้าใจยากขึ้น
  • การใช้ symlinks หรือการเปลี่ยนเส้นทางของโหนดซึ่งสามารถปิดบังตำแหน่งของแหล่งที่มาและไม่เล่นอย่างสวยงามด้วยการควบคุมแหล่งที่มา

ในท้ายที่สุดฉันตัดสินใจจัดระเบียบรหัสโดยใช้หลักการตั้งชื่อไฟล์แทนไดเรกทอรี โครงสร้างจะมีลักษณะดังนี้:

  • NPM-shrinkwrap.json
  • package.json
  • node_modules
    • ...
  • src
    • app.js
    • app.config.js
    • app.models.bar.js
    • app.models.foo.js
    • app.web.js
    • app.web.routes.js
    • ...

จากนั้นในรหัส:

var app_config = require('./app.config');
var app_models_foo = require('./app.models.foo');

หรือเพียงแค่

var config = require('./app.config');
var foo = require('./app.models.foo');

และการพึ่งพาภายนอกพร้อมใช้งานจาก node_modules ตามปกติ:

var express = require('express');

ด้วยวิธีนี้รหัสแอปพลิเคชันทั้งหมดจะถูกจัดเรียงตามลำดับชั้นเป็นโมดูลและสามารถใช้ได้กับรหัสอื่น ๆ ทั้งหมดที่เกี่ยวข้องกับรูทแอปพลิเคชัน

ข้อเสียเปรียบหลักคือแน่นอนว่าในเบราว์เซอร์ไฟล์คุณไม่สามารถขยาย / ยุบต้นไม้ราวกับว่ามันถูกจัดระเบียบในไดเรกทอรีจริง ๆ แต่ฉันชอบที่มันชัดเจนมากเกี่ยวกับที่มาของรหัสทั้งหมดและมันไม่ได้ใช้ 'วิเศษ' ใด ๆ


จากส่วนที่คุณเชื่อมโยงโซลูชัน # 7 "The Wrapper" นั้นค่อนข้างง่ายและสะดวก
Pier-Luc Gendreau

ฉันเห็นความสะดวกสบายอีกเล็กน้อย - "การย้าย" ไฟล์ไปยังโฟลเดอร์ "อื่น" กลายเป็นการเปลี่ยนชื่อ - ซึ่งง่ายกว่าการย้ายไฟล์ บวกฉันมักจะสังเกตเห็นว่าหลังจากครึ่งชั่วโมงของการทำงานในโครงการต้นไม้แอปของฉันเกือบทั้งหมดจะถูกขยายออกไป การเพิ่มพื้นที่โฟลเดอร์ 1 ระดับสามารถทำให้จัดการฐานข้อมูลขนาดใหญ่ได้และไม่แนะนำมากเกินไป../x/xซึ่งอ่านได้แล้ว
สกี

คุณกำลังสร้างโฟลเดอร์ใหม่โดยใช้จุดแทนที่จะเป็นเครื่องหมายทับเพื่อเอาชนะการขาดอย่างชัดเจนใน nodejs
Simone Gianni

9

สมมติว่ารูทโปรเจคของคุณเป็นไดเร็กตอรี่ปัจจุบันที่ใช้งานได้:

// require built-in path module
path = require('path');

// require file relative to current working directory
config = require( path.resolve('.','config.js') );

config = require('./config.js');ถูกต้องเช่นกัน
cespon

7
@cespon ไม่เพียง แต่เกี่ยวข้องกับไฟล์ที่ต้องการ
protometa

8

ฉันได้ลองวิธีแก้ไขปัญหาเหล่านี้แล้ว ฉันลงเอยด้วยการเพิ่มสิ่งนี้ไว้ที่ด้านบนของไฟล์หลัก (เช่น index.js):

process.env.NODE_PATH = __dirname;
require('module').Module._initPaths();

สิ่งนี้จะเพิ่มรูทโปรเจ็กต์ลงใน NODE_PATH เมื่อโหลดสคริปต์ ที่ช่วยให้ผมที่จะต้องใช้ไฟล์ใด ๆ var User = require('models/user')ในโครงการของฉันโดยอ้างอิงทางญาติของมันมาจากรากโครงการเช่น โซลูชันนี้จะทำงานได้ตราบใดที่คุณกำลังเรียกใช้สคริปต์หลักในรูทโครงการก่อนที่จะเรียกใช้สิ่งอื่นในโครงการของคุณ


8

คำตอบบางคำบอกว่าวิธีที่ดีที่สุดคือการเพิ่มรหัสลงใน node_module เป็นแพ็คเกจฉันเห็นด้วยและอาจเป็นวิธีที่ดีที่สุดที่จะต้องเสีย../../../แต่ก็ไม่มีวิธีใดที่จะทำได้

จากเวอร์ชั่นที่2.0.0คุณสามารถติดตั้งแพ็คเกจจากไฟล์ในเครื่องซึ่งหมายความว่าคุณสามารถสร้างโฟลเดอร์ในรูทของคุณด้วยแพ็คเกจทั้งหมดที่คุณต้องการ

-modules
 --foo
 --bar 
-app.js
-package.json

ดังนั้นใน package.json คุณสามารถเพิ่มmodules(หรือfooและbar) เป็นแพ็คเกจโดยไม่ต้องเผยแพร่หรือใช้เซิร์ฟเวอร์ภายนอกเช่นนี้:

{
  "name": "baz",
  "dependencies": {
    "bar": "file: ./modules/bar",
    "foo": "file: ./modules/foo"
  }
}

หลังจากนั้นคุณnpm installก็สามารถเข้าถึงรหัสได้var foo = require("foo")เช่นเดียวกับที่คุณทำกับแพ็คเกจอื่น ๆ ทั้งหมด

ข้อมูลเพิ่มเติมสามารถพบได้ที่นี่:

https://docs.npmjs.com/files/package.json#local-paths

และนี่คือวิธีสร้างแพ็คเกจ:

https://docs.npmjs.com/getting-started/creating-node-modules


1
"คุณสมบัตินี้มีประโยชน์สำหรับการพัฒนาออฟไลน์ในเครื่องและการสร้างการทดสอบที่จำเป็นต้องมีการติดตั้ง npm ซึ่งคุณไม่ต้องการใช้เซิร์ฟเวอร์ภายนอก แต่ไม่ควรใช้เมื่อเผยแพร่แพ็คเกจไปยังรีจิสทรีสาธารณะ"
Ryan Smith

7

คุณสามารถใช้โมดูลฉันทำUndot มันไม่มีอะไรล้ำสมัยเป็นเพียงผู้ช่วยดังนั้นคุณสามารถหลีกเลี่ยงจุดนรกด้วยความเรียบง่าย

ตัวอย่าง:

var undot = require('undot');
var User = undot('models/user');
var config = undot('config');
var test = undot('test/api/user/auth');

6

คุณสามารถกำหนดสิ่งนี้ใน app.js ของคุณ:

requireFromRoot = (function(root) {
    return function(resource) {
        return require(root+"/"+resource);
    }
})(__dirname);

และเมื่อใดก็ตามที่คุณต้องการบางสิ่งบางอย่างจากรูทไม่ว่าคุณจะอยู่ที่ไหนคุณเพียงแค่ใช้ requireFromRoot แทนที่จะต้องใช้วานิลลา ใช้งานได้ดีสำหรับฉันจนถึงตอนนี้


ขอบคุณ! ฉันคิดว่ามันค่อนข้างฉลาดและตรงไปตรงมา
Ryan

ยกโทษให้ฉันพ่อเพราะฉันทำบาป ฉันรังเพลิงนี้เพื่อ ES6 requireFromRoot = ((root) => (resource) => require(`${root}/${resource}`))(__dirname);และได้ต่อไปนี้: ชอบวิธีแก้ปัญหา แต่คุณต้องผูก __ ชื่อเล่นแบบนั้นหรือไม่?
Nuck

1
หน่วยความจำของฉันค่อนข้างขุ่นมัวในเรื่องนี้ แต่ฉันเชื่อว่าค่าการเปลี่ยนแปลงชื่อ __ ขึ้นอยู่กับไฟล์ที่ใช้ภายใน ตอนนี้อาจเป็นไปได้ว่าเนื่องจากฟังก์ชั่นถูกกำหนดไว้ในที่เดียว แต่ใช้ในหลายสถานที่ค่าจะคงที่แม้จะไม่มีการเชื่อมโยงนี้ แต่ฉันเพิ่งทำเพื่อให้แน่ใจว่านี่เป็นจริงในกรณี
user1417684

ทำสิ่งนี้มานานแล้วทำให้เกิดความเจ็บปวดในการทดสอบ envs และไม่ชอบ ไม่คุ้มกับค่าใช้จ่าย ใหม่แบบสุ่มทั่วโลกทำให้คนใหม่ไม่แน่ใจ bla bla
The Dembinski

และคุณrequireใช้ฟังก์ชันนี้อย่างไร?
Darko Maksimovic

5

นี่คือวิธีที่แท้จริงที่ฉันทำมานานกว่า 6 เดือน ฉันใช้โฟลเดอร์ชื่อ node_modules เป็นโฟลเดอร์รูทของฉันในโครงการด้วยวิธีนี้มันจะมองหาโฟลเดอร์นั้นจากทุกที่ที่ฉันเรียกว่าต้องการแน่นอน:

  • node_modules
    • โครงการของฉัน
      • index.js ฉันสามารถต้องการ ("myProject / someFolder / hey.js") แทนที่จะต้องการ ("./ someFolder / hey.js")
      • someFolder ซึ่งมี hey.js

สิ่งนี้มีประโยชน์มากขึ้นเมื่อคุณซ้อนเข้าไปในโฟลเดอร์และทำงานน้อยกว่ามากในการเปลี่ยนตำแหน่งไฟล์หากตั้งค่าในลักษณะที่แน่นอน ผมเพียง แต่ใช้ 2 ญาติต้องในของฉันapp ทั้งหมด


4
ฉันใช้วิธีการที่คล้ายกันยกเว้นว่าฉันจะเพิ่มท้องถิ่น (ของโครงการ) node_modulesใน/srcและปล่อย/node_modulesให้ผู้ขายเพื่อแยกสิ่งต่าง ๆ ดังนั้นฉันมี/src/node_modulesรหัสท้องถิ่นและ/node_modulesสำหรับผู้ขาย
Marius Balčytis

33
IMHO โฟลเดอร์ node_modules ใช้สำหรับ node_modules ไม่ใช่แนวปฏิบัติที่ดีที่จะนำโครงการทั้งหมดของคุณไปไว้ในโฟลเดอร์นั้น
McSas

2
@McSas คุณจะแนะนำอะไรเป็นทางเลือกที่จะได้รับผลเช่นเดียวกับข้างต้น?
spieglio

3
@cspiegl คุณสามารถใช้NODE_PATHตัวแปรสภาพแวดล้อม
Christopher Tarquini

5

imho วิธีที่ง่ายที่สุดเพื่อให้บรรลุนี้โดยการสร้างการเชื่อมโยงสัญลักษณ์ในการเริ่มต้นแอปnode_modules/app(หรือสิ่งที่คุณเรียกว่า) ../appซึ่งจุดที่จะต้อง require("app/my/module")แล้วคุณก็สามารถโทร ลิงก์สัญลักษณ์พร้อมใช้งานบนแพลตฟอร์มหลักทั้งหมด

อย่างไรก็ตามคุณควรแยกเนื้อหาของคุณออกเป็นโมดูลที่เล็กลงและบำรุงรักษาได้ซึ่งติดตั้งผ่านทาง npm คุณยังสามารถติดตั้งโมดูลส่วนตัวของคุณผ่าน git-url ดังนั้นจึงไม่มีเหตุผลที่จะมีหนึ่งไดเรกทอรีแอพเสาหิน


การสนับสนุนบน Windows ต้องการความรู้ในเชิงลึกเกี่ยวกับโหนดและระบบปฏิบัติการ มันสามารถ จำกัด การใช้อย่างกว้างขวางของโครงการโอเพนซอร์ส
Steven Vachon

โดยทั่วไปฉันจะไม่ใช้รูปแบบนี้สำหรับไลบรารี (ซึ่งโครงการโอเพ่นซอร์สส่วนใหญ่เป็น) อย่างไรก็ตามมันเป็นไปได้ที่จะสร้าง symlink เหล่านี้ใน hook บิวด์ npm ดังนั้นจึงไม่มีความรู้เชิงลึกที่ผู้ใช้ต้องการ
Johannes Ewald

แน่นอน แต่ Node.js บน Windows ไม่รองรับ symlink ตามค่าเริ่มต้น
Steven Vachon

4

ในโครงการของคุณเองคุณสามารถแก้ไขไฟล์. js ใด ๆ ที่ใช้ในไดเรกทอรีรากและเพิ่มเส้นทางไปยังคุณสมบัติของprocess.envตัวแปร ตัวอย่างเช่น:

// in index.js
process.env.root = __dirname;

หลังจากนั้นคุณสามารถเข้าถึงสถานที่ได้ทุกที่:

// in app.js
express = require(process.env.root);

4

คำตอบอื่น:

ลองนึกภาพโครงสร้างโฟลเดอร์นี้:

  • node_modules
    • lodash
  • src
    • subdir
      • foo.js
      • bar.js
    • main.js
  • การทดสอบ

    • test.js

จากนั้นในtest.jsคุณต้องมีไฟล์ดังนี้:

const foo = require("../src/subdir/foo");
const bar = require("../src/subdir/bar");
const main = require("../src/main");
const _ = require("lodash");

และในmain.js :

const foo = require("./subdir/foo");
const bar = require("./subdir/bar");
const _ = require("lodash");

ตอนนี้คุณสามารถใช้babelและbabel-plugin-module-resolverกับสิ่งนี้ ไฟล์babelrcเพื่อกำหนดค่า 2 โฟลเดอร์ราก:

{
    "plugins": [
        ["module-resolver", {
            "root": ["./src", "./src/subdir"]
        }]
    ]
}

ตอนนี้คุณสามารถต้องการไฟล์ในลักษณะเดียวกันในการทดสอบและในsrc :

const foo = require("foo");
const bar = require("bar");
const main = require("main");
const _ = require("lodash");

และถ้าคุณต้องการใช้ไวยากรณ์โมดูล es6 :

{
    "plugins": [
        ["module-resolver", {
            "root": ["./src", "./src/subdir"]
        }],
        "transform-es2015-modules-commonjs"
    ]
}

จากนั้นคุณนำเข้าไฟล์ในการทดสอบและsrcดังนี้:

import foo from "foo"
import bar from "bar"
import _ from "lodash"

4

เพียงแค่มาข้ามบทความนี้ซึ่งกล่าวถึงการตรวจสอบโมดูลเส้นทาง อนุญาตให้คุณกำหนดค่าฐานดังนี้:

require('app-module-path').addPath(baseDir);

3

examplesไดเรกทอรีไม่สามารถมีnode_modulesลิงก์สัญลักษณ์ไปยังรูทของโครงการproject -> ../../จึงอนุญาตให้ตัวอย่างใช้require('project')แม้ว่าจะไม่ได้ลบการแมป แต่จะอนุญาตให้ใช้แหล่งที่มาrequire('project')แทนrequire('../../')มากกว่า

ฉันทดสอบสิ่งนี้แล้วและใช้งานได้กับ v0.6.18

รายการของprojectไดเรกทอรี:

$ ls -lR project
project:
drwxr-xr-x 3 user user 4096 2012-06-02 03:51 examples
-rw-r--r-- 1 user user   49 2012-06-02 03:51 index.js

project/examples:
drwxr-xr-x 2 user user 4096 2012-06-02 03:50 node_modules
-rw-r--r-- 1 user user   20 2012-06-02 03:51 test.js

project/examples/node_modules:
lrwxrwxrwx 1 user user 6 2012-06-02 03:50 project -> ../../

เนื้อหาของการindex.jsกำหนดค่าให้กับคุณสมบัติของexportsวัตถุและเรียกใช้console.logด้วยข้อความที่ระบุว่ามันเป็นสิ่งจำเป็น เนื้อหาของมีtest.jsrequire('project')


คุณสามารถแสดงรหัสแหล่งที่มาของการทดสอบของคุณได้ไหม ดีและมันจะทำงานถ้าฉันจะต้องมี ('project.a') ด้วยวิธีนี้
Totty.js

คุณหมายถึงrequire('project.a')อะไร ฉันคิดว่าอาจหมายถึงrequire('project/a')แม้ว่าจะrequire('project').aเป็นไปได้เช่นกัน?
Dan D.

แต่ด้วยตัวอย่างของคุณฉันจะต้องสร้างโฟลเดอร์เหล่านั้นในแต่ละโฟลเดอร์ที่มีโมดูลที่ต้องการวิธีการที่ต้องการ อย่างไรก็ตามคุณจะต้องดูแลเกี่ยวกับช่วงเวลาของ "../" ตามโฟลเดอร์
Totty.js

จริงๆแล้วลิงก์จะต้องอยู่ในnode_modulesไดเรกทอรีในพาเรนต์ที่ใกล้ที่สุดของทั้งไฟล์และลิงก์ก็จะเหมือนกันทั้งคู่ ดูnodejs.org/api/…
Dan D.

และจะสัมพันธ์กับตำแหน่งนั้น ตัวอย่างเช่นproject/node_modules/project -> ../.
Dan D.

2

หากใครกำลังมองหาวิธีอื่นในการแก้ไขปัญหานี้นี่คือความพยายามของฉัน:

https://www.npmjs.com/package/use-import

แนวคิดพื้นฐาน: คุณสร้างไฟล์ JSON ในรูทของโครงการที่จับคู่พา ธ ไฟล์ของคุณกับชื่อชวเลข (หรือใช้ use-automapperเพื่อทำเพื่อคุณ) จากนั้นคุณสามารถร้องขอไฟล์ / โมดูลโดยใช้ชื่อเหล่านั้น ชอบมาก

var use = require('use-import');
var MyClass = use('MyClass');

ดังนั้นมีที่


2

สิ่งที่ฉันต้องทำคือใช้ประโยชน์จากวิธีโหลดโหนดจากไดเรกทอรี node_module สำหรับสิ่งนี้

หากมีใครพยายามโหลดโมดูล "สิ่ง" ใครจะทำสิ่งที่ต้องการ

require('thing');

โหนดจะค้นหาไดเรกทอรี 'thing' ในไดเรกทอรี 'node_module'

เนื่องจาก node_module เป็นปกติที่รูทของโครงการเราสามารถใช้ความสอดคล้องนี้ (หาก node_module ไม่ได้อยู่ที่รูทคุณจะมีอาการปวดหัวที่เกิดขึ้นเองอื่น ๆ เพื่อจัดการ)

ถ้าเราเข้าไปในไดเร็กตอรี่แล้วถอยออกมาเราจะได้พา ธ ที่สอดคล้องกับรูทของโปรเจ็กต์โหนด

require('thing/../../');

จากนั้นถ้าเราต้องการเข้าถึงไดเรกทอรี / happy เราจะทำเช่นนี้

require('thing/../../happy');

แม้ว่ามันจะค่อนข้างแฮ็คเล็กน้อย แต่ฉันรู้สึกว่าการทำงานของวิธีการโหลด node_modules เปลี่ยนแปลงจะมีปัญหาที่ใหญ่กว่าที่จะจัดการกับ พฤติกรรมนี้ควรจะสอดคล้องกัน

เพื่อทำให้สิ่งต่าง ๆ ชัดเจนฉันทำสิ่งนี้เพราะชื่อของโมดูลไม่สำคัญ

require('root/../../happy');

ฉันใช้มันเมื่อเร็ว ๆ นี้สำหรับ angular2 ฉันต้องการโหลดบริการจากรูท

import {MyService} from 'root/../../app/services/http/my.service';

เกี่ยวกับการอ้างอิงเชิงมุมด้วยแอปพลิเคชัน CLI มาตรฐานคุณสามารถนำเข้าได้อย่างง่ายดายนอกจากsrc/app/my.serviceนี้คุณยังสามารถกำหนดค่า VSC ให้ใช้การนำเข้าที่ไม่เกี่ยวข้องสำหรับไฟล์ typescript
Ploppy

2

ฉันเขียนแพ็กเกจขนาดเล็กนี้ที่ช่วยให้คุณต้องการแพ็กเกจตามเส้นทางสัมพัทธ์ของพวกเขาจากรูทโครงการโดยไม่ต้องแนะนำตัวแปรทั่วโลกหรือค่าเริ่มต้นของโหนดที่แทนที่

https://github.com/Gaafar/pkg-require

มันใช้งานได้เช่นนี้

// create an instance that will find the nearest parent dir containing package.json from your __dirname
const pkgRequire = require('pkg-require')(__dirname);

// require a file relative to the your package.json directory 
const foo = pkgRequire('foo/foo')

// get the absolute path for a file
const absolutePathToFoo = pkgRequire.resolve('foo/foo')

// get the absolute path to your root directory
const packageRootPath = pkgRequire.root()

บางครั้งฉันมีแพ็คเกจส่วนตัวในโครงการหลักสคริปต์นี้จะแตกหัก นอกจากนั้นฉันไม่แน่ใจว่าจะทำงานได้ดีกับ webpack (ในกรณีที่คุณใช้ webpack กับ node.js เช่นเดียวกับฉัน)
Totty.js

หากคุณมีไดเร็กทอรีที่ซ้อนกันพร้อมไฟล์แพ็กเกจ dir แต่ละตัวจะสามารถเรียกใช้ไฟล์ภายในแพ็คเกจได้เท่านั้น นั่นเป็นพฤติกรรมที่คุณต้องการใช่ไหม ฉันไม่ได้ทดสอบกับ webpack
gafi

สิ่งนี้ทำงานได้อย่างสมบูรณ์แบบสำหรับโครงการที่เรียบง่ายและง่ายกว่าคำตอบอื่น ๆ
byxor

2

เพียงแค่ต้องการติดตามคำตอบที่ยอดเยี่ยมจากPaolo Morettiและ Browserify หากคุณใช้ transpiler (เช่น babel, typescript) และคุณมีโฟลเดอร์แยกต่างหากสำหรับซอร์สและรหัส transpiled เช่นsrc/และdist/คุณสามารถใช้รูปแบบของโซลูชันต่าง ๆ ดังนี้

node_modules

ด้วยโครงสร้างไดเรกทอรีต่อไปนี้:

app
  node_modules
    ... // normal npm dependencies for app
  src
    node_modules
      app
        ... // source code
  dist
    node_modules
      app
        ... // transpiled code

จากนั้นคุณสามารถให้ babel ฯลฯ ไปยังsrcไดเรกทอรีtranspile ไปยังdistไดเรกทอรี

symlink

การใช้ symlink ทำให้เราสามารถกำจัดการซ้อนในระดับหนึ่งได้:

app
  node_modules
    ... // normal npm dependencies for app
  src
    node_modules
      app // symlinks to '..'
    ... // source code
  dist
    node_modules
      app // symlinks to '..'
    ... // transpiled code

ข้อแม้กับ Babel --copy ไฟล์--copy-filesธงbabelไม่ได้จัดการกับ symlinks ดี มันอาจทำให้การนำทางไปสู่..symlink และดูไฟล์ซ้ำไม่สิ้นสุด วิธีแก้ปัญหาคือการใช้โครงสร้างไดเรกทอรีต่อไปนี้:

app
  node_modules
    app // symlink to '../src'
    ... // normal npm dependencies for app
  src
    ... // source code
  dist
    node_modules
      app // symlinks to '..'
    ... // transpiled code

ด้วยวิธีนี้รหัสภายใต้srcจะยังคงมีการappแก้ไขsrcในขณะที่บาเบลจะไม่เห็นลิงก์อีกต่อไป


ขอบคุณ แต่ฉันจะไม่แนะนำให้ทำเวทมนตร์นี้ ก่อนอื่นคุณจะสูญเสียการนำเข้าทั้งหมดพวกเขาจะไม่ถูกคำนวณโดย IDE ของคุณ หากคุณใช้เครื่องมืออื่น ๆ เช่นประเภทการไหลมันจะไม่ทำงานอย่างถูกต้อง
Totty.js

ในความเป็นจริงแล้วโฟลว์นั้นใช้งานได้ในกรณีของฉันซึ่งไม่น่าแปลกใจเพราะวิธีแก้ปัญหานั้นขึ้นอยู่กับโมเดลความละเอียดของโมดูลโหนดมาตรฐานและ symlink ดังนั้นมันจึงไม่วิเศษสำหรับเครื่องมือเช่นการไหลที่จะเข้าใจ แต่ IDEs นั้นแตกต่างกัน
user716468

2

ผมกำลังมองหาเรียบง่ายเดียวกันแน่นอนที่จะต้องใช้ไฟล์จากระดับใดและฉันพบโมดูลนามแฝง

เพียงติดตั้ง:

npm i --save module-alias

เปิดไฟล์ package.json ของคุณที่นี่คุณสามารถเพิ่มนามแฝงสำหรับเส้นทางของคุณเช่น

"_moduleAliases": {
 "@root"      : ".", // Application's root
 "@deep"      : "src/some/very/deep/directory/or/file",
 "@my_module" : "lib/some-file.js",
 "something"  : "src/foo", // Or without @. Actually, it could be any string
}

และใช้นามแฝงของคุณเพียงแค่:

require('module-alias/register')
const deep = require('@deep')
const module = require('something')


1

เรากำลังจะลองวิธีใหม่ในการแก้ไขปัญหานี้

นำตัวอย่างจากโครงการที่รู้จักอื่น ๆ เช่นฤดูใบไม้ผลิและ guice เราจะกำหนดวัตถุ "บริบท" ซึ่งจะมีคำสั่ง "ต้องการ" ทั้งหมด

วัตถุนี้จะถูกส่งผ่านไปยังโมดูลอื่นทั้งหมดเพื่อใช้งาน

ตัวอย่างเช่น

var context = {}

context.module1 = require("./module1")( { "context" : context } )
context.module2 = require("./module2")( { "context" : context } )

สิ่งนี้ต้องการให้เราเขียนแต่ละโมดูลเป็นฟังก์ชั่นที่รับ opts ซึ่งดูเหมือนว่าเราจะเป็นแนวปฏิบัติที่ดีที่สุดต่อไป ..

module.exports = function(context){ ... }

จากนั้นคุณจะอ้างถึงบริบทแทนที่จะต้องการสิ่งต่างๆ

var module1Ref = context.moduel1;

ถ้าคุณต้องการคุณสามารถเขียนลูปเพื่อทำประโยคคำสั่ง

var context = {};
var beans = {"module1" : "./module1","module2" : "./module2" }; 
for ( var i in beans ){
    if ( beans.hasOwnProperty(i)){
         context[i] = require(beans[i])(context);
    }
};

สิ่งนี้จะทำให้ชีวิตง่ายขึ้นเมื่อคุณต้องการเยาะเย้ย (การทดสอบ) และแก้ปัญหาของคุณไปพร้อมกันในขณะที่ทำให้โค้ดของคุณสามารถใช้ซ้ำได้เป็นแพคเกจ

คุณยังสามารถใช้รหัสการเริ่มต้นบริบทอีกครั้งโดยแยกการประกาศ bean จากมัน ตัวอย่างเช่นmain.jsไฟล์ของคุณอาจมีลักษณะเช่นนั้น

var beans = { ... }; // like before
var context = require("context")(beans); // this example assumes context is a node_module since it is reused.. 

วิธีนี้ยังนำไปใช้กับไลบรารีภายนอกไม่จำเป็นต้องใช้รหัสอย่างหนักทุกครั้งที่เราต้องการ - แต่จะต้องมีการดูแลเป็นพิเศษเนื่องจากการส่งออกของพวกเขาไม่ใช่ฟังก์ชั่นที่คาดหวังบริบท

ต่อมาเราสามารถกำหนดถั่วเป็นฟังก์ชั่น - ซึ่งจะช่วยให้เราสามารถrequireโมดูลที่แตกต่างกันตามสภาพแวดล้อม - แต่มันอยู่นอกขอบเขตของหัวข้อนี้


1

ผมมีปัญหากับปัญหาเดียวกันนี้ดังนั้นผมเขียนแพคเกจที่เรียกว่าได้แก่

รวมถึงจัดการการหาโฟลเดอร์รูทของโปรเจ็กต์ของคุณโดยการหาไฟล์ package.json ของคุณจากนั้นส่งผ่านอาร์กิวเมนต์พา ธ ที่คุณให้แก่ native need () โดยไม่ยุ่งกับพา ธ ที่เกี่ยวข้องทั้งหมด ฉันคิดว่านี่ไม่ใช่สิ่งทดแทนสำหรับ require () แต่เป็นเครื่องมือสำหรับการจัดการไฟล์หรือไลบรารีที่ไม่ได้ทำแพคเกจ / ไม่ใช่บุคคลที่สาม สิ่งที่ต้องการ

var async = require('async'),
    foo   = include('lib/path/to/foo')

ฉันหวังว่านี่จะเป็นประโยชน์


1

หากไฟล์จุดเริ่มต้นของแอป js (คือคนที่คุณทำงานจริง "โหนด" บน) อยู่ในไดเรกทอรีรากโครงการของคุณคุณสามารถทำเช่นนี้ได้อย่างง่ายดายจริงๆกับโมดูล RootPath NPM เพียงติดตั้งผ่าน

npm install --save rootpath

... จากนั้นที่จุดเริ่มต้นของไฟล์ js ให้เพิ่ม:

require('rootpath')();

จากจุดนั้นไปข้างหน้าการโทรทั้งหมดต้องสัมพันธ์กับรูทโปรเจ็กต์ - เช่นrequire('../../../config/debugging/log'); กลายเป็นrequire('config/debugging/log');(โดยที่โฟลเดอร์ config อยู่ในรูทโปรเจ็กต์)


1

ในบรรทัดง่าย ๆ คุณสามารถเรียกโฟลเดอร์ของคุณเองเป็นโมดูลได้

เพื่อสิ่งที่เราต้องการ: โมดูล global และ app-module-path

ที่นี่ "App-module-path" เป็นโมดูลช่วยให้คุณสามารถเพิ่มไดเรกทอรีเพิ่มเติมไปยังเส้นทางการค้นหาโมดูล Node.js และ "global" คือสิ่งใดก็ตามที่คุณแนบกับวัตถุนี้จะมีอยู่ทุกที่ในแอปของคุณ

ตอนนี้ลองดูตัวอย่างนี้:

global.appBasePath = __dirname;

require('app-module-path').addPath(appBasePath);

__dirname เป็นไดเรกทอรีใช้งานปัจจุบันของโหนดคุณสามารถกำหนดพา ธ ของคุณเองที่นี่เพื่อค้นหาพา ธ สำหรับโมดูล

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.