Xác định gốc dự án từ ứng dụng node.js đang chạy


336

Có cách nào tốt hơn là process.cwd()xác định thư mục gốc của tiến trình node.js đang chạy không? Một cái gì đó tương tự như Rails.root, nhưng đối với Node.js. Tôi đang tìm kiếm thứ gì đó dễ dự đoán và đáng tin cậy nhất có thể.


1
Bất kỳ cơ hội nào bạn có thể không chấp nhận câu trả lời được chấp nhận, sai, được chấp nhận?
Dave Newton

10
hãy thử process.env.PWD... xem câu trả lời của tôi dưới đây.
Alexander Mills

Câu trả lời:


664

Có một số cách để tiếp cận điều này, mỗi cách đều có ưu và nhược điểm riêng:

request.main.filename

Từ http://nodejs.org/api/modules.html :

Khi một tệp được chạy trực tiếp từ Node, require.mainđược đặt thành của nó module. Điều đó có nghĩa là bạn có thể xác định xem tệp đã được chạy trực tiếp hay chưa bằng cách kiểm trarequire.main === module

modulecung cấp một thuộc filenametính (thường tương đương với __filename), điểm vào của ứng dụng hiện tại có thể được lấy bằng cách kiểm tra require.main.filename.

Vì vậy, nếu bạn muốn có thư mục cơ sở cho ứng dụng của mình, bạn có thể làm:

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

Ưu & Nhược điểm

Điều này sẽ hoạt động hiệu quả trong hầu hết thời gian, nhưng nếu bạn đang chạy ứng dụng của mình với trình khởi chạy như pm2 hoặc chạy thử nghiệm mocha , phương pháp này sẽ không thành công.

global.X

Node có một đối tượng không gian tên chung được gọi global- bất cứ thứ gì bạn đính kèm vào đối tượng này sẽ có sẵn ở mọi nơi trong ứng dụng của bạn. Vì vậy, trong index.js(hoặc app.jsbất kỳ tên tệp ứng dụng chính nào của bạn), bạn chỉ có thể xác định một biến toàn cục:

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

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

Ưu & Nhược điểm

Hoạt động nhất quán nhưng bạn phải dựa vào một biến toàn cục, có nghĩa là bạn không thể dễ dàng sử dụng lại các thành phần / v.v.

process.cwd ()

Điều này trả về thư mục làm việc hiện tại. Không đáng tin cậy chút nào, vì nó hoàn toàn phụ thuộc vào thư mục mà quy trình được khởi chạy từ :

$ 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

app-root-path

Để giải quyết vấn đề này, tôi đã tạo một mô-đun nút có tên là app-root-path . Cách sử dụng rất đơn giản:

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

Các app-root-path Module này sử dụng các kỹ thuật khác nhau để xác định đường dẫn gốc của ứng dụng, có tính đến các module được cài đặt trên toàn thế giới (ví dụ, nếu ứng dụng của bạn đang chạy trong /var/www/nhưng các module được cài đặt trong~/.nvm/v0.x.x/lib/node/ ). Nó sẽ không hoạt động 100% thời gian, nhưng nó sẽ hoạt động trong hầu hết các tình huống phổ biến.

Ưu & Nhược điểm

Hoạt động mà không cần cấu hình trong hầu hết các trường hợp. Cũng cung cấp một số phương pháp tiện lợi bổ sung (xem trang dự án). Vấn đề lớn nhất là nó sẽ không hoạt động nếu:

  • Bạn đang sử dụng trình khởi chạy, như pm2
  • , mô-đun không được cài đặt bên trong thư mục ứng dụng của bạn node_modules(ví dụ: nếu bạn đã cài đặt nó trên toàn cầu)

Bạn có thể giải quyết vấn đề này bằng cách thiết lập một APP_ROOT_PATHbiến môi trường hoặc bằng cách gọi .setPath()mô-đun, nhưng trong trường hợp đó, có lẽ bạn nên sử dụng globalphương pháp này.

Biến môi trường NODE_PATH

Nếu bạn đang tìm cách xác định đường dẫn gốc của ứng dụng hiện tại, một trong những giải pháp trên có thể phù hợp nhất với bạn. Mặt khác, nếu bạn đang cố gắng giải quyết vấn đề tải mô-đun ứng dụng một cách đáng tin cậy, tôi thực sự khuyên bạn nên xem xét NODE_PATHbiến môi trường.

Hệ thống Mô-đun của Node tìm kiếm các mô-đun ở nhiều vị trí khác nhau. Một trong những vị trí này là bất cứ nơi nào process.env.NODE_PATHđiểm . Nếu bạn đặt biến môi trường này, thì bạn có thểrequire mô-đun với bộ tải mô-đun tiêu chuẩn mà không có bất kỳ thay đổi nào khác.

Ví dụ: nếu bạn đặt NODE_PATHthành /var/www/lib, những điều sau sẽ hoạt động tốt:

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

Một cách tuyệt vời để làm điều này là sử dụng npm:

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

Bây giờ bạn có thể bắt đầu ứng dụng của mình với npm startvà bạn là vàng. Tôi kết hợp điều này với mô-đun thực thi-nút-đường dẫn của mình , điều này ngăn việc vô tình tải ứng dụng mà không NODE_PATHđược thiết lập. Để kiểm soát nhiều hơn việc thực thi các biến môi trường, hãy xem checkenv .

Một gotcha: NODE_PATH phải được đặt bên ngoài ứng dụng nút. Bạn không thể làm điều gì đó như process.env.NODE_PATH = path.resolve(__dirname)vì trình tải mô-đun lưu danh sách các thư mục mà nó sẽ tìm kiếm trước khi ứng dụng của bạn chạy.

[thêm 4/6/16] Một mô-đun thực sự hứa hẹn khác cố gắng giải quyết vấn đề này là gợn sóng .


1
@Kevin trong trường hợp này, mocha là điểm nhập của ứng dụng của bạn. Đây chỉ là một ví dụ về lý do tại sao việc tìm kiếm "gốc dự án" lại rất khó - nó phụ thuộc rất nhiều vào tình huống và ý bạn là "gốc dự án".
inxilpro

1
@Kevin Tôi hoàn toàn hiểu. Quan điểm của tôi là chỉ rằng khái niệm về "gốc của dự án" là nhiều dễ dàng hơn cho một con người để hiểu hơn một máy tính . Nếu bạn muốn có một phương pháp chống đánh lừa, bạn cần phải cấu hình nó. Sử dụng require.main.filenamesẽ hoạt động hầu hết thời gian, nhưng không phải mọi lúc.
inxilpro

2
Hơi liên quan: đây là một cách cực kỳ thông minh để tổ chức các dự án Node của bạn để bạn không cần phải lo lắng về vấn đề này rất nhiều: allanhortle.com/2015/02/04/...
inxilpro

1
Tôi không biết liệu có sự thay đổi trong pm2 hay sự thay đổi với Node.js nhưng require.main.filenamedường như hoạt động với pm2. Không biết về mocha.
Justin Warkentin

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

55

__dirnamekhông phải là một toàn cầu; nó cục bộ cho mô-đun hiện tại nên mỗi tệp có giá trị cục bộ riêng, khác nhau.

Nếu bạn muốn thư mục gốc của quá trình đang chạy, bạn có thể muốn sử dụng process.cwd() .

Nếu bạn muốn khả năng dự đoán và độ tin cậy, thì bạn có thể cần phải đặt một biến môi trường nhất định vào một yêu cầu của ứng dụng. Ứng dụng của bạn đang tìm kiếm MY_APP_HOME(Hoặc bất cứ thứ gì) và nếu nó ở đó và ứng dụng tồn tại trong thư mục đó thì tất cả đều ổn. Nếu nó không được xác định hoặc thư mục không chứa ứng dụng của bạn thì nó sẽ thoát ra với lỗi nhắc người dùng tạo biến. Nó có thể được đặt như một phần của quá trình cài đặt.

Bạn có thể đọc các biến môi trường trong nút với một cái gì đó như process.env.MY_ENV_VARIABLE.


2
Nếu được sử dụng một cách thận trọng, điều này có thể hoạt động khá tốt. Nhưng nó sẽ cho kết quả khác nhau khi làm bin/server.jsvs cd bin && server.js. (giả sử các js file được đánh dấu là thực thi)
Myrne Stol

1
Việc sử dụng process.cwd()đã hoạt động như một cái duyên đối với tôi, ngay cả khi chạy thử nghiệm mocha. Cảm ơn bạn!
Diogo Eichert 23/03/18

51

1- tạo một tệp trong thư mục gốc của dự án, gọi nó là settings.js

2- bên trong tệp này thêm mã này

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

3- bên trong node_modules tạo một mô-đun mới đặt tên là "cài đặt" và bên trong mô-đun index.js viết mã này:

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

4- và bất cứ lúc nào bạn muốn thư mục dự án của mình chỉ cần sử dụng

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

bằng cách này, bạn sẽ có tất cả các thư mục dự án liên quan đến tệp này;)


37
-1: Để tải tập tin cài đặt, bạn cần một đường dẫn, sau đó lấy đường dẫn tham chiếu đến tập tin đó? Không giải quyết bất cứ điều gì ...
goliatone

2
Đã ủng hộ vì đã dành thời gian để xem xét và chỉnh sửa. Nó vẫn cảm thấy giòn, nhưng sức mạnh mà chỉ là do có không phải là một cách tốt hơn để đạt được điều này
goliatone

8
Một điều mà người dùng sẽ muốn ghi nhớ với cách tiếp cận này node_moduleslà thường bị loại trừ khỏi kiểm soát phiên bản. Vì vậy, nếu bạn làm việc với một nhóm hoặc cần sao chép kho lưu trữ của mình, bạn sẽ phải đưa ra một giải pháp khác để giữ cho tệp cài đặt đó được đồng bộ hóa.
Travesty 3

@ Travesty3 mô-đun cài đặt thực sự là một mô-đun trống đang xuất nội dung của tệp trong gốc dự án: P
Fareed Alnamrouti

@goliatone Với giải pháp của anh ấy, bạn có thể lấy tệp từ bất kỳ đâu mà không cần biết đường dẫn của nó, tất cả những gì bạn phải biết là "cài đặt". Nếu không có nó, bạn sẽ phải biết rõ ràng có bao nhiêu thư mục cần sao lưu cho đến khi bạn đến được thư mục dự án. Điều này hoạt động vì nút tự động tìm kiếm node_modules và luôn biết đó là đâu.

29

cách dễ nhất để lấy root toàn cục ( giả sử bạn sử dụng NPM để chạy ứng dụng node.js 'npm start', v.v. )

var appRoot = process.env.PWD;

Nếu bạn muốn xác minh chéo những điều trên

Giả sử bạn muốn kiểm tra chéo process.env.PWDvới cài đặt của ứng dụng node.js của bạn. nếu bạn muốn một số bài kiểm tra thời gian chạy để kiểm tra tính hợp lệ process.env.PWD, bạn có thể kiểm tra chéo nó bằng mã này (mà tôi đã viết có vẻ hoạt động tốt). Bạn có thể kiểm tra chéo tên của thư mục cuối cùng trong appRoot với npm_package_name trong tệp package.json của mình, ví dụ:

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

bạn cũng có thể sử dụng mô-đun NPM này: require('app-root-path')hoạt động rất tốt cho mục đích này


6
Điều này hoạt động tốt trên (hầu hết) hệ thống unix. Ngay khi bạn muốn mô-đun / ứng dụng npm của mình hoạt động trên Windows, PWDnó vẫn chưa được xác định và điều này không thành công.
Jeremy Wiebe

1
process.cwd()
Muhammad Umer

@MuhammadUmer tại sao process.cwd()luôn giống với gốc dự án?
Alexander Mills

nếu bạn gọi nó trong file gốc sau đó nó muốn được
Muhammad Umer

14

Tôi nhận thấy điều này hoạt động nhất quán đối với tôi, ngay cả khi ứng dụng được gọi từ một thư mục con, vì nó có thể xảy ra với một số khung thử nghiệm, như Mocha:

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

Tại sao nó hoạt động:

Khi chạy nút tạo một sổ đăng ký các đường dẫn đầy đủ của tất cả các tệp đã tải. Các mô-đun được tải đầu tiên và do đó ở đầu sổ đăng ký này. Bằng cách chọn phần tử đầu tiên của sổ đăng ký và trả về đường dẫn trước thư mục 'node_modules', chúng tôi có thể xác định gốc của ứng dụng.

Đó chỉ là một dòng mã, nhưng vì lợi ích đơn giản (lợi ích của tôi), tôi đã đóng hộp đen nó vào một mô-đun NPM:

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

Thưởng thức!


1
process.mainModule deprectaed kể từ: v14.0.0 - sử dụng require.main.paths[0].split('node_modules')[0].slice(0, -1);thay thế.
RobC

12

Tất cả các "root dirs" này chủ yếu cần giải quyết một số đường dẫn ảo thành đường dẫn cọc thực, vì vậy có thể bạn nên xem xét path.resolve?

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

10

Đơn giản như thêm dòng này vào mô-đun của bạn trong thư mục gốc, thường thì nó là app.js

global.__basedir = __dirname;

Sau đó, _basedir sẽ có thể truy cập được vào tất cả các mô-đun của bạn.


8

Có thể bạn có thể thử duyệt ngược từ trên __filenamecho đến khi tìm thấy một package.jsonvà quyết định đó là thư mục chính mà tệp hiện tại của bạn thuộc về.


7

Trên thực tế, tôi thấy giải pháp có lẽ nhỏ nhặt cũng mạnh mẽ nhất: bạn chỉ cần đặt tệp sau tại thư mục gốc của dự án của bạn: root-path.js có mã sau:

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


4

Một kỹ thuật mà tôi thấy hữu ích khi sử dụng express là thêm phần sau vào app.js trước khi bất kỳ tuyến nào khác của bạn được thiết lập

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

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

Không cần sử dụng hình cầu và bạn có đường dẫn của thư mục gốc như một thuộc tính của đối tượng yêu cầu.

Điều này hoạt động nếu app.js của bạn nằm trong thư mục gốc của dự án, theo mặc định, nó là.


4

Thêm cái này vào đâu đó ở đầu tệp ứng dụng chính của bạn (ví dụ: app.js):

global.__basedir = __dirname;

Điều này đặt một biến toàn cục sẽ luôn tương đương với dir cơ sở của ứng dụng của bạn. Sử dụng nó giống như bất kỳ biến nào khác:

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

Đơn giản...


4

Tôi biết điều này đã quá muộn. Nhưng chúng tôi có thể tìm nạp URL gốc bằng hai phương pháp

Phương pháp thứ nhất

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

Phương pháp thứ hai

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

Liên kết tham khảo: - https://gist.github.com/geekiam/e2e3e0325abd9023d3a3


3

Có một INIT_CWDtài sản trên process.env. Đây là những gì tôi hiện đang làm việc với dự án của mình.

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

Chúc may mắn...


1
Hoạt động giống như một sự quyến rũ đối với một gói thao tác dự án mà nó đang được gọi từ bước sau cài đặt. Tuy nhiên, tôi vẫn chưa thử nghiệm nó trong một lớp phụ thuộc khác, nơi một dự án sử dụng một phụ thuộc sử dụng gói của tôi.
JamesDev

1
@JamesDev, INIT_CWDgiải quyết vấn đề directorymà từ đó npm-scriptđã phát sinh.
Aakash

2

nếu bạn muốn xác định gốc dự án từ một ứng dụng node.js đang chạy, bạn cũng có thể đơn giản.

process.mainModule.path

1

Ở đầu tệp chính, thêm:

mainDir = __dirname;

Sau đó, sử dụng nó trong bất kỳ tệp nào bạn cần:

console.log('mainDir ' + mainDir);
  • mainDirđược định nghĩa trên toàn cầu, nếu bạn chỉ cần nó trong tệp hiện tại - hãy sử dụng __dirnamethay thế.
  • tập tin chính thường nằm trong thư mục gốc của dự án và được đặt tên như main.js, index.js, gulpfile.js.

1

Làm cho nó sexy sexy🏻.

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


Ba bước đơn giản để giải quyết vấn đề của con đường xấu xí.

  1. Cài đặt gói: npm install sexy-require --save
  2. Bao gồm require('sexy-require')một lần ở đầu hồ sơ đăng ký chính của bạn.

    require('sexy-require');
    const routers = require('/routers');
    const api = require('$api');
    ...
    
  3. Bước tùy chọn. Cấu hình đường dẫn có thể được xác định trong .pathstệp trên thư mục gốc của dự án của bạn.

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

Có vẻ tốt, quá tệ là nó có một cái tên nực cười như vậy.
JHH

@JHH à ... Tôi phải tìm một cái tên hay hơn
sultan

1

Thao tác này sẽ chuyển xuống cây thư mục cho đến khi nó chứa một node_modulesthư mục, thường chỉ ra gốc dự án của bạn:

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

Nó cũng đảm bảo rằng không có node_modulestrong đường dẫn trả về, vì điều đó có nghĩa là nó được chứa trong một gói cài đặt lồng nhau.


1

process.mainModuleđang bị phản đối từ v 14.0.0. Khi tham khảo câu trả lời, vui lòng sử dụng require.main , phần còn lại vẫn giữ.

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

Lấy tất cả các đường dẫn trong các mô-đun chính và lọc ra những đường dẫn có "node_modules", sau đó lấy danh sách đường dẫn đầu tiên còn lại. Hành vi không mong muốn sẽ không gây ra lỗi, chỉ là một undefined.

Hoạt động tốt cho tôi, ngay cả khi gọi tức là $ mocha.


1

Mở đầu

Đây là một câu hỏi rất cũ nhưng nó dường như vẫn còn gây nhức nhối vào năm 2020 như năm 2012. Tôi đã kiểm tra tất cả các câu trả lời khác và không thể tìm thấy một kỹ thuật nào (lưu ý rằng điều này có những hạn chế của nó, nhưng tất cả những câu khác thì không áp dụng trong mọi tình huống).

GIT + quy trình con

Nếu bạn đang sử dụng GIT làm hệ thống kiểm soát phiên bản của mình, vấn đề xác định gốc của dự án có thể được giảm xuống (mà tôi sẽ coi là gốc thích hợp của dự án - sau cùng, bạn muốn VCS của mình có phạm vi hiển thị đầy đủ nhất có thể) :

truy xuất đường dẫn gốc của kho lưu trữ

Vì bạn phải chạy một lệnh CLI để làm điều đó, chúng tôi sẽ cần tạo ra một quy trình con. Ngoài ra, vì gốc dự án rất ít có khả năng thay đổi thời gian chạy giữa chừng, chúng tôi có thể sử dụng phiên bản đồng bộ củachild_process API mô-đun khi khởi động.

Tôi thấy spawnSync()mình là người phù hợp nhất với công việc. Đối với lệnh thực sự để chạy, git worktree(với--porcelain tùy chọn để dễ phân tích cú pháp) là tất cả những gì chúng ta cần để truy xuất đường dẫn gốc tuyệt đối.

Trong ví dụ này, tôi đã chọn trả về một mảng đường dẫn vì có thể có nhiều hơn một worktree (mặc dù chúng có khả năng có các đường dẫn chung) chỉ để chắc chắn. Lưu ý rằng khi chúng tôi sử dụng lệnh CLI, shelltùy chọn phải được đặt thành true(bảo mật không phải là vấn đề vì không có đầu vào không đáng tin cậy).

Phương pháp so sánh và dự phòng

Hiểu rằng có thể xảy ra trường hợp không thể truy cập VCS, tôi đã đưa vào một số dự phòng sau khi phân tích tài liệu và các câu trả lời khác. Tóm lại, các giải pháp được đề xuất tổng hợp (không bao gồm các mô-đun của bên thứ ba & gói cụ thể):

| Giải pháp | Lợi thế | Vấn đề chính |
| ------------------------ | ----------------------- | -------------------------------- |
| `__tên tệp` | trỏ tới tệp mô-đun | liên quan đến mô-đun |
| `__dirname` | trỏ đến mô-đun dir | giống như `__filename` |
| `node_modules` đi bộ trên cây | root gần như đảm bảo | cây phức tạp đi bộ nếu lồng vào nhau |
| `path.resolve (". ")` | root nếu CWD là root | giống như `process.cwd ()` |
| `process.argv [1]` | giống như `__filename` | giống như `__filename` |
| `process.env.INIT_CWD` | trỏ tới `npm run` dir | yêu cầu khởi chạy `npm` && CLI |
| `process.env.PWD` | trỏ tới dir hiện tại | liên quan đến (là) khởi chạy dir |
| `process.cwd ()` | giống như ʻenv.PWD` | `process.chdir (path)` trong thời gian chạy |
| `request.main.filename` | root nếu `=== mô-đun` | không thành công trên mô-đun `request`d

Từ bảng so sánh ở trên, phổ biến nhất là hai cách tiếp cận:

  • require.main.filenamenhư một cách dễ dàng để có được quyền root nếu require.main === moduleđược đáp ứng
  • node_modulesđi bộ trên cây được đề xuất gần đây sử dụng một giả định khác:

nếu thư mục của mô-đun có node_modulesdir bên trong, nó có thể là thư mục gốc

Đối với ứng dụng chính, nó sẽ lấy gốc ứng dụng và cho mô-đun - gốc dự án của nó.

Dự phòng 1. Đi bộ trên cây

Việc triển khai của tôi sử dụng một cách tiếp cận lỏng lẻo hơn bằng cách dừng lại khi tìm thấy thư mục đích vì đối với một mô-đun nhất định, gốc của nó là gốc dự án của nó. Người ta có thể chuỗi các cuộc gọi hoặc mở rộng nó để làm cho độ sâu tìm kiếm có thể định cấu hình:

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

Dự phòng 2. Mô-đun chính

Việc triển khai thứ hai là tầm thường

/**
 * @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] :
            [];
    };

Thực hiện

Tôi khuyên bạn nên sử dụng xe tập đi trên cây làm dự phòng vì nó linh hoạt hơn:

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

Nhược điểm

Rõ ràng nhất là việc cài đặt và khởi tạo GIT có thể không mong muốn / không thể tin được (lưu ý phụ: việc cài đặt GIT trên máy chủ sản xuất không phải là hiếm, cũng không phải là không an toàn ). Có thể được dàn xếp bằng các dự phòng như mô tả ở trên.

Ghi chú

  1. Một vài ý tưởng để mở rộng thêm phương pháp tiếp cận 1:
  • giới thiệu cấu hình như một tham số chức năng
  • export chức năng biến nó thành một mô-đun
  • kiểm tra xem GIT đã được cài đặt và / hoặc khởi chạy chưa

Người giới thiệu

  1. git worktree tài liệu tham khảo
  2. spawnSync tài liệu tham khảo
  3. require.main tài liệu tham khảo
  4. path.dirname() tài liệu tham khảo

0

Tạo một hàm trong 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

Tôi sử dụng cái này.

Đối với mô-đun của tôi có tên mymodule

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


0

Bạn chỉ cần thêm đường dẫn thư mục gốc vào biến ứng dụng express và lấy đường dẫn này từ ứng dụng. Đối với điều này, hãy thêm app.set('rootDirectory', __dirname);vào tệp index.js hoặc app.js của bạn. Và sử dụng req.app.get('rootDirectory')để lấy đường dẫn thư mục gốc trong mã của bạn.


0

Câu hỏi cũ, tôi biết, tuy nhiên không có câu hỏi nào đề cập đến việc sử dụng progress.argv. Mảng argv bao gồm tên đường dẫn và tên tệp đầy đủ (có hoặc không có phần mở rộng .js) được sử dụng làm tham số được thực thi bởi nút. Bởi vì nó cũng có thể chứa cờ, bạn phải lọc nó.

Đây không phải là một ví dụ bạn có thể trực tiếp sử dụng (vì sử dụng khuôn khổ của riêng tôi) nhưng tôi nghĩ nó cung cấp cho bạn một số ý tưởng về cách thực hiện. Tôi cũng sử dụng phương pháp bộ nhớ cache để tránh việc gọi hàm này làm căng thẳng hệ thống quá nhiều, đặc biệt khi không có phần mở rộng nào được chỉ định (và yêu cầu kiểm tra sự tồn tại của tệp), ví dụ:

node myfile

hoặc là

node myfile.js

Đó là lý do tôi lưu nó vào bộ nhớ cache, hãy xem thêm mã bên dưới.


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

Việc tìm kiếm đường dẫn gốc của một ứng dụng điện tử có thể trở nên khó khăn. Bởi vì đường dẫn gốc là khác nhau đối với tiến trình chính và trình kết xuất trong các điều kiện khác nhau như điều kiện sản xuất, phát triển và đóng gói.

Tôi đã viết một gói npm electron-root-path để nắm bắt đường dẫn gốc của một ứng dụng electron.

$ 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

Điều này sẽ làm:

path.join(...process.argv[1].split(/\/|\\/).slice(0, -1))


-1

Thử path._makeLong('some_filename_on_root.js');

thí dụ:

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

Điều đó sẽ trả về đường dẫn đầy đủ từ thư mục gốc của ứng dụng nút của bạn (cùng vị trí của package.json)


-1

Chỉ dùng:

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

điều này hoạt động tuyệt vời! path.resolve (".") cũng hoạt động
Noel Schenk

Điều đó chỉ cung cấp cho thư mục hiện tại, mà có thể không phải là thư mục gốc.
orad

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.