ระบุรูทโปรเจ็กต์จากแอ็พพลิเคชันที่กำลังรัน node.js


315

มีวิธีที่ดีกว่าprocess.cwd()การกำหนดไดเรกทอรีรูทของกระบวนการ node.js หรือไม่? บางสิ่งบางอย่างที่เทียบเท่ากับRails.rootแต่สำหรับ Node.js ฉันกำลังมองหาบางสิ่งที่สามารถคาดการณ์ได้และเชื่อถือได้มากที่สุด


1
โอกาสใดที่คุณสามารถยกเลิกการตอบรับที่ยอมรับผิดตอบได้?
Dave Newton

9
ลองprocess.env.PWD... ดูคำตอบของฉันด้านล่าง
Alexander Mills

คำตอบ:


624

มีหลายวิธีในการเข้าถึงสิ่งนี้แต่ละคนมีข้อดีและข้อเสียของตัวเอง:

require.main.filename

จากhttp://nodejs.org/api/modules.html :

เมื่อไฟล์ถูกเรียกใช้โดยตรงจากโหนดrequire.mainจะถูกตั้งค่าเป็นmoduleมีการตั้งค่าของมันซึ่งหมายความว่าคุณสามารถตรวจสอบว่าไฟล์นั้นถูกเรียกใช้โดยตรงโดยการทดสอบrequire.main === module

เพราะmoduleยังมีfilenameสถานที่ให้บริการ (ปกติเทียบเท่า__filename) require.main.filenameจุดเริ่มต้นของการประยุกต์ใช้ในปัจจุบันสามารถหาได้โดยการตรวจสอบ

ดังนั้นหากคุณต้องการไดเรกทอรีฐานสำหรับแอปของคุณคุณสามารถทำได้:

var path = require('path');
var appDir = path.dirname(require.main.filename);

ข้อเสียข้อดี

วิธีนี้จะใช้งานได้ดีที่สุด แต่ถ้าคุณใช้แอพของคุณด้วยตัวเรียกใช้เช่นpm2หรือเรียกใช้มอคค่าการทดสอบวิธีนี้จะล้มเหลว

global.X

โหนดมีวัตถุเนมสเปซส่วนกลางที่เรียกว่าglobal- สิ่งใดก็ตามที่คุณแนบกับวัตถุนี้จะมีอยู่ทุกที่ในแอปของคุณ ดังนั้นในindex.js(หรือapp.jsชื่อไฟล์หลักของคุณ) คุณสามารถกำหนดตัวแปรกลางได้

// index.js
var path = require('path');
global.appRoot = path.resolve(__dirname);

// lib/moduleA/component1.js
require(appRoot + '/lib/moduleB/component2.js');

ข้อเสียข้อดี

ทำงานได้อย่างสม่ำเสมอ แต่คุณต้องพึ่งพาตัวแปรทั่วโลกซึ่งหมายความว่าคุณไม่สามารถนำส่วนประกอบ / etc มาใช้ใหม่ได้อย่างง่ายดาย

process.cwd ()

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

$ cd /home/demo/
$ mkdir subdir
$ echo "console.log(process.cwd());" > subdir/demo.js
$ node subdir/demo.js
/home/demo
$ cd subdir
$ node demo.js
/home/demo/subdir

แอปรากเส้นทาง

เพื่อแก้ไขปัญหานี้เราได้สร้างโมดูลโหนดเรียกว่าแอปรากเส้นทาง การใช้งานง่าย:

var appRoot = require('app-root-path');
var myModule = require(appRoot + '/lib/my-module.js');

แอปรากเส้นทางโมดูลใช้เทคนิคที่แตกต่างกันในการกำหนดเส้นทางรากของ app ที่คำนึงถึงการติดตั้งโมดูลทั่วโลก (ตัวอย่างเช่นถ้าแอปของคุณกำลังทำงานใน/var/www/แต่โมดูลที่ติดตั้งใน~/.nvm/v0.x.x/lib/node/ ) มันจะไม่ทำงาน 100% ของเวลา แต่มันจะทำงานในสถานการณ์ที่พบบ่อยที่สุด

ข้อเสียข้อดี

ทำงานโดยไม่มีการกำหนดค่าในสถานการณ์ส่วนใหญ่ ยังมีวิธีอำนวยความสะดวกเพิ่มเติมที่ดีอีกด้วย ข้อเสียที่ใหญ่ที่สุดคือมันจะไม่ทำงานถ้า:

  • คุณกำลังใช้ตัวเรียกใช้งานเช่น pm2
  • และโมดูลนั้นไม่ได้รับการติดตั้งในnode_modulesไดเรกทอรีของแอพ(ตัวอย่างเช่นหากคุณติดตั้งไว้ทั่วโลก)

คุณสามารถแก้ไขปัญหานี้ได้โดยการตั้งค่าAPP_ROOT_PATHตัวแปรสภาพแวดล้อมหรือโดยการโทรหา.setPath()โมดูล แต่ในกรณีนี้คุณน่าจะใช้งานglobalวิธีนี้ได้

ตัวแปรสภาวะแวดล้อม NODE_PATH

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

ระบบ Modulesของ Node ค้นหาโมดูลในหลากหลายตำแหน่ง หนึ่งในสถานที่เหล่านี้เป็นที่ใดก็ตามที่process.env.NODE_PATHจุด หากคุณตั้งค่าตัวแปรสภาพแวดล้อมนี้คุณก็สามารถทำได้requireโมดูลด้วยตัวโหลดโมดูลมาตรฐานโดยไม่มีการเปลี่ยนแปลงอื่นใด

ตัวอย่างเช่นถ้าคุณตั้งค่าNODE_PATHเพื่อ/var/www/libที่ต่อไปนี้จะทำงานได้ดี:

require('module2/component.js');
// ^ looks for /var/www/lib/module2/component.js

วิธีที่ยอดเยี่ยมในการทำเช่นนี้คือใช้npm:

"scripts": {
    "start": "NODE_PATH=. node app.js"
}

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

หนึ่ง gotcha: NODE_PATH ต้องตั้งค่านอกแอพโหนด คุณไม่สามารถทำอะไรเช่นprocess.env.NODE_PATH = path.resolve(__dirname)เนื่องจากตัวโหลดโมดูลจะแคชรายการไดเรกทอรีที่จะค้นหาก่อนที่แอปของคุณจะทำงาน

[เพิ่ม 4/6/16]อีกโมดูลที่มีแนวโน้มมากที่ความพยายามที่จะแก้ปัญหานี้คือหยัก


1
@Kevin ในกรณีนี้ mocha เป็นจุดเริ่มต้นของใบสมัครของคุณ นี่เป็นเพียงตัวอย่างของสาเหตุที่การค้นหา "รากโครงการ" นั้นยากมาก - ขึ้นอยู่กับสถานการณ์และสิ่งที่คุณหมายถึงโดย "รากโครงการ"
inxilpro

1
@ เควินฉันเข้าใจอย่างสมบูรณ์ จุดของฉันเป็นเพียงว่าแนวคิดของ "รากโครงการ" เป็นมากง่ายขึ้นสำหรับมนุษย์ที่จะเข้าใจกว่าคอมพิวเตอร์ หากคุณต้องการวิธีการป้องกันคนโง่คุณต้องกำหนดค่า การใช้require.main.filenameจะได้ผลเกือบตลอดเวลา แต่ไม่ตลอดเวลา
inxilpro

2
เกี่ยวข้องกับตัวเอง: นี่เป็นวิธีที่ชาญฉลาดในการจัดระเบียบโครงการโหนดของคุณเพื่อที่คุณจะได้ไม่ต้องกังวลเกี่ยวกับปัญหานี้อีกมาก: allanhortle.com/2015/02/04/…
inxilpro

1
ฉันไม่ทราบว่ามีการเปลี่ยนแปลงใน pm2 หรือการเปลี่ยนแปลงกับ Node.js แต่require.main.filenameดูเหมือนจะทำงานกับ pm2 ไม่ทราบเกี่ยวกับมอคค่า
Justin Warkentin

8
path.parse(process.mainModule.filename).dir
Cory Robinson

53

__dirnameไม่ใช่ทั่วโลก เป็นแบบโลคัลกับโมดูลปัจจุบันดังนั้นแต่ละไฟล์มีค่าโลคัลของตนเองแตกต่างกัน

process.cwd()หากคุณต้องการไดเรกทอรีรากของกระบวนการทำงานคุณอาจไม่ต้องการที่จะใช้

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

process.env.MY_ENV_VARIABLEคุณสามารถอ่านตัวแปรสภาพแวดล้อมในโหนดกับสิ่งที่ต้องการ


2
หากใช้ด้วยความระมัดระวังสิ่งนี้อาจใช้ได้ดี แต่มันจะให้ผลลัพธ์ที่แตกต่างกันเมื่อทำVSbin/server.js cd bin && server.js(สมมติว่าไฟล์ js เหล่านี้ถูกทำเครื่องหมายว่าสามารถเรียกใช้งานได้)
Myrne Stol

1
การใช้งานprocess.cwd()ได้ผลเหมือนมีเสน่ห์สำหรับฉันแม้ว่าจะทำการทดสอบมอคค่า ขอบคุณ!
Diogo Eichert

49

1- สร้างไฟล์ในโปรเจ็กต์รูทเรียกว่าsettings.js

2- ในไฟล์นี้เพิ่มรหัสนี้

module.exports = {
    POST_MAX_SIZE : 40 , //MB
    UPLOAD_MAX_FILE_SIZE: 40, //MB
    PROJECT_DIR : __dirname
};

3- ภายใน node_modules สร้างชื่อโมดูลใหม่มัน "การตั้งค่า" และภายใน index.js โมดูลเขียนรหัสนี้:

module.exports = require("../../settings");

4- และทุกเวลาที่คุณต้องการไดเรกทอรีโครงการของคุณเพียงแค่ใช้

var settings = require("settings");
settings.PROJECT_DIR; 

ด้วยวิธีนี้คุณจะมีไดเรกทอรีโครงการทั้งหมดที่เกี่ยวข้องกับไฟล์นี้;)


33
-1: ในการโหลดไฟล์การตั้งค่าที่คุณต้องการพา ธ จากนั้นรับพา ธ อ้างอิงไปยังไฟล์นั้น ไม่แก้อะไรเลย ...
goliatone

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

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

@ Travesty3 โมดูลการตั้งค่าเป็นโมดูลเปล่าที่ส่งออกเนื้อหาของไฟล์ในรูทโปรเจ็กต์: P
Fareed Alnamrouti

@goliatone ด้วยวิธีการแก้ปัญหาของเขาคุณสามารถรับไฟล์ได้จากทุกที่โดยไม่ต้องรู้เส้นทางของมันสิ่งที่คุณต้องรู้ก็คือ "การตั้งค่า" หากไม่มีคุณจะต้องทราบอย่างชัดเจนว่ามีกี่โฟลเดอร์ที่ต้องสำรองออกจนกว่าคุณจะไปถึงไดเรกทอรีโครงการ สิ่งนี้ใช้ได้เนื่องจากโหนดค้นหา node_modules โดยอัตโนมัติและรู้ว่าอยู่ที่ไหน

26

วิธีที่ง่ายที่สุดในการรับรูทโกลบอล ( สมมติว่าคุณใช้ NPM เพื่อรันแอป node.js ของคุณ 'เริ่มต้น npm' เป็นต้น )

var appRoot = process.env.PWD;

หากคุณต้องการข้ามการตรวจสอบข้างต้น

สมมติว่าคุณต้องการตรวจสอบข้ามprocess.env.PWDกับการตั้งค่าของคุณ node.js แอป หากคุณต้องการให้การทดสอบรันไทม์บางอย่างเพื่อตรวจสอบความถูกต้องของprocess.env.PWDคุณสามารถตรวจสอบได้ด้วยรหัสนี้ (ที่ฉันเขียนซึ่งดูเหมือนว่าจะทำงานได้ดี) คุณสามารถตรวจสอบชื่อของโฟลเดอร์สุดท้ายใน appRoot ด้วย npm_package_name ในไฟล์ package.json ของคุณตัวอย่างเช่น:

    var path = require('path');

    var globalRoot = __dirname; //(you may have to do some substring processing if the first script you run is not in the project root, since __dirname refers to the directory that the file is in for which __dirname is called in.)

    //compare the last directory in the globalRoot path to the name of the project in your package.json file
    var folders = globalRoot.split(path.sep);
    var packageName = folders[folders.length-1];
    var pwd = process.env.PWD;
    var npmPackageName = process.env.npm_package_name;
    if(packageName !== npmPackageName){
        throw new Error('Failed check for runtime string equality between globalRoot-bottommost directory and npm_package_name.');
    }
    if(globalRoot !== pwd){
        throw new Error('Failed check for runtime string equality between globalRoot and process.env.PWD.');
    }

คุณยังสามารถใช้โมดูล NPM นี้ได้require('app-root-path')ซึ่งทำงานได้ดีมากสำหรับวัตถุประสงค์นี้


5
มันใช้งานได้ดีกับระบบยูนิกซ์ (ส่วนใหญ่) ทันทีที่คุณต้องการให้โมดูล / แอป npm ทำงานบน Windows PWDจะไม่ได้กำหนดและสิ่งนี้จะล้มเหลว
Jeremy Wiebe

1
process.cwd()
Muhammad Umer

@MuhammadUmer ทำไมจะprocess.cwd()เหมือนกันกับรูทโปรเจคเสมอ
Alexander Mills

ถ้าคุณเรียกมันในไฟล์รูทก็จะเป็น
Muhammad Umer

14

ฉันพบว่ามันใช้งานได้อย่างสม่ำเสมอสำหรับฉันแม้ว่าจะมีการเรียกใช้แอปพลิเคชันจากโฟลเดอร์ย่อยเนื่องจากสามารถใช้เฟรมเวิร์กทดสอบบางอย่างเช่น Mocha:

process.mainModule.paths[0].split('node_modules')[0].slice(0, -1);

ทำไมมันถึงได้ผล

ที่รันไทม์โหนดสร้างรีจิสตรีของพา ธ เต็มของไฟล์ที่โหลดทั้งหมด โมดูลจะถูกโหลดขึ้นมาก่อนและอยู่ด้านบนสุดของรีจิสตรีนี้ โดยการเลือกองค์ประกอบแรกของรีจิสตรีและคืนค่าพา ธ ก่อนไดเรกทอรี 'node_modules' เราจะสามารถระบุรูทของแอปพลิเคชันได้

มันเป็นเพียงโค้ดหนึ่งบรรทัด แต่เพื่อความเรียบง่าย (สาเกของฉัน) ฉันได้บรรจุมันลงในโมดูล NPM:

https://www.npmjs.com/package/node-root.pddivine

สนุก!


1
process.mainModule deprectaed ตั้งแต่: v14.0.0 - ใช้require.main.paths[0].split('node_modules')[0].slice(0, -1);แทน
RobC

10

"root dirs" ทั้งหมดเหล่านี้ส่วนใหญ่จำเป็นต้องแก้ไขเส้นทางเสมือนบางส่วนไปยังเส้นทางกองจริงดังนั้นคุณควรจะดูที่path.resolve?

var path= require('path');
var filePath = path.resolve('our/virtual/path.ext');

9

ง่ายๆแค่เพิ่มบรรทัดนี้ลงในโมดูลของคุณในรูทปกติคือ app.js

global.__basedir = __dirname;

จากนั้น _basedir จะสามารถเข้าถึงโมดูลทั้งหมดของคุณได้


8

บางทีคุณอาจลองสำรวจไปข้างบน__filenameจนกว่าจะเจอ a package.jsonและตัดสินใจว่าเป็นไดเรกทอรีหลักที่ไฟล์ปัจจุบันของคุณเป็นของ


7

ที่จริงแล้วฉันพบว่าวิธีแก้ปัญหาเล็กน้อยอาจมีประสิทธิภาพมากที่สุด: คุณเพียงวางไฟล์ต่อไปนี้ที่ไดเรกทอรีรากของโครงการของคุณ: root-path.js ซึ่งมีรหัสต่อไปนี้:

import * as path from 'path'
const projectRootPath = path.resolve(__dirname)
export const rootPath = projectRootPath

4

เทคนิคที่ฉันพบว่ามีประโยชน์เมื่อใช้ express คือการเพิ่มสิ่งต่อไปนี้ใน app.js ก่อนที่เส้นทางอื่น ๆ ของคุณจะถูกตั้งค่า

// set rootPath
app.use(function(req, res, next) {
  req.rootPath = __dirname;
  next();
});

app.use('/myroute', myRoute);

ไม่จำเป็นต้องใช้ globals และคุณมีเส้นทางของไดเรกทอรีรากเป็นคุณสมบัติของวัตถุคำขอ

สิ่งนี้จะทำงานได้ถ้าแอพของคุณอยู่ในรูทของโปรเจคซึ่งโดยค่าเริ่มต้นแล้ว


4

เพิ่มที่นี้ไว้ที่จุดเริ่มต้นของไฟล์หลักของแอพ (เช่น app.js):

global.__basedir = __dirname;

ชุดนี้เป็นตัวแปรส่วนกลางที่จะเทียบเท่ากับ dir ฐานของแอปของคุณเสมอ ใช้มันเหมือนกับตัวแปรอื่น ๆ :

const yourModule = require(__basedir + '/path/to/module.js');

ง่าย ...


3

ฉันรู้ว่าอันนี้สายเกินไปแล้ว แต่เราสามารถดึง URL รูทได้ด้วยสองวิธี

วิธีที่ 1

var path = require('path');
path.dirname(require.main.filename);

วิธีที่ 2

var path = require('path');
path.dirname(process.mainModule.filename);

ลิงค์อ้างอิง: - https://gist.github.com/geekiam/e2e3e0325abd9023d3a3


3

มีความเป็นทรัพย์สินในINIT_CWD process.envนี่คือสิ่งที่ฉันกำลังทำงานกับในโครงการของฉัน

const {INIT_CWD} = process.env; // process.env.INIT_CWD 
const paths = require(`${INIT_CWD}/config/paths`);

โชคดี...


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

1
@JamesDev INIT_CWDแก้ไขdirectoryจากสิ่งที่npm-scriptexectued
Akash

2

หากคุณต้องการกำหนดรูทโปรเจ็กต์จากแอ็พพลิเคชันที่กำลังทำงาน node.js คุณก็สามารถทำได้เช่นกัน

process.mainModule.path

1

ที่ด้านบนของไฟล์หลักเพิ่ม:

mainDir = __dirname;

จากนั้นใช้ในไฟล์ใดก็ได้ที่คุณต้องการ:

console.log('mainDir ' + mainDir);
  • mainDirถูกกำหนดไว้ทั่วโลกหากคุณต้องการใช้ในไฟล์ปัจจุบันเท่านั้น - ใช้__dirnameแทน
  • ไฟล์หลักมักจะอยู่ในโฟลเดอร์รากของโครงการและการตั้งชื่อเช่นmain.js, ,index.jsgulpfile.js

1

ฉันใช้สิ่งนี้

สำหรับโมดูลของฉันชื่อ mymodule

var BASE_DIR = __dirname.replace(/^(.*\/mymodule)(.*)$/, '$1')


1

ทำให้มันเซ็กซี่💃🏻

const users = require('../../../database/users'); // 👎 what you have
// OR
const users = require('$db/users'); // 👍 no matter how deep you are
const products = require('/database/products'); // 👍 alias or pathing from root directory


สามขั้นตอนง่าย ๆ ในการแก้ปัญหาเส้นทางที่น่าเกลียด

  1. ติดตั้งแพ็คเกจ: npm install sexy-require --save
  2. รวมrequire('sexy-require')หนึ่งครั้งที่ด้านบนสุดของไฟล์แอปพลิเคชันหลักของคุณ

    require('sexy-require');
    const routers = require('/routers');
    const api = require('$api');
    ...
  3. ขั้นตอนเพิ่มเติม การกำหนดค่าพา ธ สามารถกำหนดไว้ใน.pathsไฟล์ในไดเรกทอรีรากของโครงการของคุณ

    $db = /server/database
    $api-v1 = /server/api/legacy
    $api-v2 = /server/api/v2

ดูเหมือนว่าดีแย่มากที่มันมีชื่อที่ไร้สาระ
JHH

@JHH ดี ... ฉันต้องหาชื่อที่ดีกว่า
สุลต่าน

1

ขั้นตอนนี้จะลดทอนไดเรกทอรีไดเรกทอรีจนกว่าจะมีnode_modulesไดเรกทอรีซึ่งโดยปกติจะระบุรากโครงการของคุณ:

const fs = require('fs')
const path = require('path')

function getProjectRoot(currentDir = __dirname.split(path.sep)) {
  if (!currentDir.length) {
    throw Error('Could not find project root.')
  }
  const nodeModulesPath = currentDir.concat(['node_modules']).join(path.sep)
  if (fs.existsSync(nodeModulesPath) && !currentDir.includes('node_modules')) {
    return currentDir.join(path.sep)
  }
  return this.getProjectRoot(currentDir.slice(0, -1))
}

นอกจากนี้ยังตรวจสอบให้แน่ใจว่าไม่มีnode_modulesในเส้นทางที่ส่งคืนเนื่องจากหมายความว่ามีอยู่ในการติดตั้งแพคเกจที่ซ้อนกัน


1

process.mainModuleจะเลิกตั้งแต่วี 14.0.0 เมื่อพูดถึงคำตอบโปรดใช้ require.mainส่วนที่เหลือยังคงอยู่

process.mainModule.paths
  .filter(p => !p.includes('node_modules'))
  .shift()

รับพา ธ ทั้งหมดในโมดูลหลักและกรองออกด้วย "node_modules" จากนั้นรับพา ธ แรกของรายการพา ธ ที่เหลืออยู่ พฤติกรรมที่ไม่คาดคิดจะไม่เกิดข้อผิดพลาดเพียงundefinedอย่างเดียว

$ mochaทำงานได้ดีสำหรับฉันแม้เมื่อโทรคือ


0

สร้างฟังก์ชั่นใน app.js

/*Function to get the app root folder*/

var appRootFolder = function(dir,level){
    var arr = dir.split('\\');
    arr.splice(arr.length - level,level);
    var rootFolder = arr.join('\\');
    return rootFolder;
}

// view engine setup
app.set('views', path.join(appRootFolder(__dirname,1),'views'));

0

คุณสามารถเพิ่มเส้นทางไดเรกทอรีรากในตัวแปรแอพด่วนและรับเส้นทางนี้จากแอพ สำหรับการเพิ่มนี้app.set('rootDirectory', __dirname);ในไฟล์ index.js หรือ app.js ของคุณ และใช้req.app.get('rootDirectory')สำหรับรับเส้นทางไดเรกทอรีรากในรหัสของคุณ


0

คำถามเก่า ๆ ฉันรู้ แต่ก็ไม่มีคำถามที่พูดถึงการใช้ progress.argvแต่ไม่มีการกล่าวถึงคำถามกับการใช้งาน อาร์เรย์ argv มีชื่อพา ธ เต็มและชื่อไฟล์ (มีหรือไม่มีนามสกุล. js) ที่ใช้เป็นพารามิเตอร์ที่จะดำเนินการโดยโหนด เนื่องจากสิ่งนี้ยังสามารถมีธงคุณต้องกรองสิ่งนี้

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

node myfile

หรือ

node myfile.js

นั่นคือเหตุผลที่ฉันแคชดูรหัสด้านล่าง


function getRootFilePath()
{
        if( !isDefined( oData.SU_ROOT_FILE_PATH ) )
        {
            var sExt = false;

            each( process.argv, function( i, v )
            {
                 // Skip invalid and provided command line options
                if( !!v && isValidString( v ) && v[0] !== '-' )
                {
                    sExt = getFileExt( v );

                    if( ( sExt === 'js' ) || ( sExt === '' && fileExists( v+'.js' )) )
                    {

                        var a = uniformPath( v ).split("/"); 

                         // Chop off last string, filename
                        a[a.length-1]='';

                         // Cache it so we don't have to do it again.
                        oData.SU_ROOT_FILE_PATH=a.join("/"); 

                         // Found, skip loop
                        return true;
                    }
                }
            }, true ); // <-- true is: each in reverse order
        }

        return oData.SU_ROOT_FILE_PATH || '';
    }
}; 

0

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

ฉันได้เขียนแพ็กเกจอิเล็กตรอนรูทพา ธเพื่อจับภาพรูทพา ธ ของแอปอิเล็กตรอน

$ npm install electron-root-path

or 

$ yarn add electron-root-path


// Import ES6 way
import { rootPath } from 'electron-root-path';

// Import ES2015 way
const rootPath = require('electron-root-path').rootPath;

// e.g:
// read a file in the root
const location = path.join(rootPath, 'package.json');
const pkgInfo = fs.readFileSync(location, { encoding: 'utf8' });



0

คำนำ

นี่เป็นคำถามที่เก่ามาก แต่ดูเหมือนว่าจะยังประสาทในปี 2020 เช่นในปี 2012 ฉันได้ตรวจสอบคำตอบอื่น ๆ ทั้งหมดและไม่สามารถหา tecnique (โปรดทราบว่านี่มีข้อ จำกัด แต่คนอื่น ๆ ทั้งหมดไม่ใช่ สามารถใช้ได้ในทุกสถานการณ์เช่นกัน)

กระบวนการลูก GIT +

หากคุณใช้ GIT เป็นระบบควบคุมเวอร์ชันของคุณปัญหาในการพิจารณารูทโปรเจ็กต์สามารถลดลงเป็น (ซึ่งฉันจะพิจารณารูทที่เหมาะสมของโปรเจค - หลังจากทั้งหมดคุณต้องการให้ VCS ของคุณมีขอบเขตการมองเห็นอย่างเต็มที่) :

เส้นทางที่เก็บข้อมูล retreive

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

ฉันพบว่าspawnSync()เหมาะสมที่สุดสำหรับงาน สำหรับคำสั่งจริงที่จะเรียกใช้git worktree(พร้อม--porcelainตัวเลือกเพื่อความสะดวกในการแยกวิเคราะห์) เป็นสิ่งที่เราต้องเรียกเส้นทางรากที่แน่นอน

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

วิธีการเปรียบเทียบและทางเลือก

การเข้าใจว่าสถานการณ์ที่ VCS ไม่สามารถเข้าถึงได้ฉันได้รวมข้อผิดพลาดสองสามข้อหลังจากวิเคราะห์เอกสารและคำตอบอื่น ๆ เพื่อสรุปผลการแก้ปัญหาที่นำเสนอต้มลงไป (ไม่รวมโมดูลของบุคคลที่สาม & แพคเกจเฉพาะ):

| โซลูชัน | ข้อได้เปรียบ | ปัญหาหลัก
| ------------------------ | ----------------------- | -------------------------------- |
| `__filename` | | ชี้ไปที่ไฟล์โมดูล | สัมพันธ์กับโมดูล |
| `__dirname` | ชี้ไปที่โมดูล dir | เหมือนกับ "__filename" |
| `node_modules` tree walk | รับประกันเกือบราก | ต้นไม้สลับซับซ้อนหากซ้อนกัน |
| `path.resolve (". ")` | รูตถ้า CWD เป็นรูต | เหมือนกับ `process.cwd ()` |
| `process.argv [1]` | เหมือนกับ "__filename" | เหมือนกับ "__filename" |
| `process.env.INIT_CWD` | ชี้ไปที่ `npm run` dir | ต้องการ `npm '&& CLI launch |
| `process.env.PWD` | ชี้ไปที่ dir ปัจจุบัน สัมพันธ์กับ (คือ) เรียกใช้ dir |
| `process.cwd ()` | เหมือนกับ `env.PWD` | `process.chdir (เส้นทาง)` ที่ runtime |
| `require.main.filename` | | รูตถ้า `=== โมดูล '| ล้มเหลวในโมดูล `require`d |

จากตารางเปรียบเทียบด้านบนสากลมากที่สุดมีสองวิธี:

  • require.main.filenameเป็นวิธีง่าย ๆ ในการรูทถ้าrequire.main === moduleเจอ
  • node_modulesTree Walk เสนอเมื่อเร็ว ๆ นี้ใช้สมมติฐานอื่น:

ถ้าไดเรกทอรีของโมดูลมีnode_modulesdir อยู่ภายในก็น่าจะเป็นรูต

สำหรับแอพหลักมันจะรับรูทแอพและโมดูล - รูทโปรเจ็กต์

ทางเลือก 1. เดินต้นไม้

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

/**
 * @summary gets root by walking up node_modules
 * @param {import("fs")} fs
 * @param {import("path")} pt
 */
const getRootFromNodeModules = (fs, pt) =>

    /**
     * @param {string} [startPath]
     * @returns {string[]}
     */
    (startPath = __dirname) => {

        //avoid loop if reached root path
        if (startPath === pt.parse(startPath).root) {
            return [startPath];
        }

        const isRoot = fs.existsSync(pt.join(startPath, "node_modules"));

        if (isRoot) {
            return [startPath];
        }

        return getRootFromNodeModules(fs, pt)(pt.dirname(startPath));
    };

ทางเลือกที่ 2 โมดูลหลัก

การใช้งานครั้งที่สองนั้นไม่สำคัญ

/**
 * @summary gets app entry point if run directly
 * @param {import("path")} pt
 */
const getAppEntryPoint = (pt) =>

    /**
     * @returns {string[]}
     */
    () => {

        const { main } = require;

        const { filename } = main;

        return main === module ?
            [pt.parse(filename).dir] :
            [];
    };

การดำเนินงาน

ฉันขอแนะนำให้ใช้ tree walker เป็นทางเลือกเพราะมันมีความหลากหลายมากกว่า:

const { spawnSync } = require("child_process");
const pt = require('path');
const fs = require("fs");

/**
 * @summary returns worktree root path(s)
 * @param {function : string[] } [fallback]
 * @returns {string[]}
 */
const getProjectRoot = (fallback) => {

    const { error, stdout } = spawnSync(
        `git worktree list --porcelain`,
        {
            encoding: "utf8",
            shell: true
        }
    );

    if (!stdout) {
        console.warn(`Could not use GIT to find root:\n\n${error}`);
        return fallback ? fallback() : [];
    }

    return stdout
        .split("\n")
        .map(line => {
            const [key, value] = line.split(/\s+/) || [];
            return key === "worktree" ? value : "";
        })
        .filter(Boolean);
};

ข้อเสีย

สิ่งที่ชัดเจนที่สุดคือการติดตั้ง GIT และเริ่มต้นซึ่งอาจไม่พึงประสงค์ / ไม่น่าเชื่อ (หมายเหตุด้าน: การติดตั้ง GIT บนเซิร์ฟเวอร์ที่ใช้งานจริงไม่ใช่เรื่องแปลกและไม่ปลอดภัยแม้ว่า) สามารถไกล่เกลี่ยได้โดยการล้มตามที่อธิบายไว้ข้างต้น

หมายเหตุ

  1. ความคิดสองสามข้อสำหรับการขยายแนวทางเพิ่มเติม 1:
    • แนะนำ config เป็นพารามิเตอร์ฟังก์ชั่น
    • export ฟังก์ชั่นที่จะทำให้มันเป็นโมดูล
    • ตรวจสอบว่าติดตั้ง GIT และ / หรือเริ่มต้นแล้ว

อ้างอิง

  1. git worktree การอ้างอิง
  2. spawnSync การอ้างอิง
  3. require.main การอ้างอิง
  4. path.dirname() การอ้างอิง


-1

ลอง path._makeLong('some_filename_on_root.js');

ตัวอย่าง:

cons path = require('path');
console.log(path._makeLong('some_filename_on_root.js');

สิ่งนั้นจะส่งคืนพา ธ แบบเต็มจากรูทของแอปพลิเคชันโหนดของคุณ (ตำแหน่งเดียวกันของ package.json)


-1

เพียงใช้:

 path.resolve("./") ... output is your project root directory

มันใช้งานได้ดี! path.resolve (".") ทำงานได้ดี
Noel Schenk

นั่นให้ไดเรกทอรีปัจจุบันเท่านั้นซึ่งอาจไม่ใช่ไดเรกทอรีราก
orad

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