itsource

ES6 모듈을 사용하는 경우 Node.js의 __dirname에 대한 대안

mycopycode 2023. 5. 22. 21:02
반응형

ES6 모듈을 사용하는 경우 Node.js의 __dirname에 대한 대안

나는 깃발을 사용합니다.--experimental-modulesES6 모듈을 사용하기 위해 노드 응용 프로그램을 실행할 때.

그러나 이 플래그를 사용할 때 메타 변수__dirname사용할 수 없습니다.다음에 저장된 동일한 문자열을 가져올 수 있는 다른 방법이 있습니까?__dirname이 모드와 호환됩니까?

Node.js 10.12부터는 여러 개의 파일을 만들 필요가 없고 여러 플랫폼에 걸쳐 파일 이름의 특수 문자를 처리할 수 있는 대안이 있습니다.

import { dirname } from 'path';
import { fileURLToPath } from 'url';

const __dirname = dirname(fileURLToPath(import.meta.url));

2021년 가장 표준화된 방식

import { URL } from 'url'; // in Browser, the URL in native accessible on window

const __filename = new URL('', import.meta.url).pathname;
// Will contain trailing slash
const __dirname = new URL('.', import.meta.url).pathname;

그리고 잊어버려요.join하려면 현재파서만다사음오시용십하을면들려경로를일에를 .URL

const pathToAdjacentFooFile = new URL('./foo.txt', import.meta.url).pathname;
const pathToUpperBarFile = new URL('../bar.json', import.meta.url).pathname;

노드 10.12 +...

모듈에서 작업한다고 가정하면 이 솔루션은 작동해야 하며 __filename 지원도 제공합니다.

import path from 'node:path';
import { fileURLToPath } from 'node:url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

좋은 점은 공통에 대한 요구 사항()을 지원하는 코드가 두 줄밖에 없다는 것입니다.JS 모듈.이를 위해 다음을 추가할 수 있습니다.

import { createRequireFromPath } from 'module';
const require = createRequireFromPath(__filename); 

대부분의 경우 외부 리소스가 아닌 Node.js(ES 모듈 포함)에 고유한 것을 사용하는 경우 대부분의 경우사용하지 않아도 됩니다.읽기(스트리밍)를 위한 대부분의 기본 방법은 +를 지원합니다.import.meta.url공식 문서 자체가 시사하는 바와 같이,

메서드에 대한 설명에서 볼 수 있듯이 매개 변수에는 지원되는 형식이 표시되며, 예는 다음과 같습니다.

방법 경로 매개 변수 지원
fs.readFile(path[, options], callback) <string>,<Buffer>, <URL>,<integer>
fs.readFileSync(path[, options]) <string>,<Buffer>, <URL>,<integer>
fs.readdir(path[, options], callback) <string>,<Buffer>, <URL>
fs.readdirSync(path[, options]) <string>,<Buffer>, <URL>,<integer>
fsPromises.readdir(path[, options]) <string>,<Buffer>, <URL>
fsPromises.readFile(path[, options]) <string>,<Buffer>, <URL>,<FileHandle>

래서로.new URL('<path or file>', import.meta.url)해결되므로 문자열을 처리하고 나중에 연결할 변수를 만들 필요가 없습니다.

예:

스크립트와 동일한 수준에서 필요 없이 파일을 읽을 수 있는 방법 확인__filename또는 해결 방법:

import { readFileSync } from 'fs';

const output = readFileSync(new URL('./foo.txt', import.meta.url));

console.log(output.toString());

스크립트 디렉터리의 모든 파일 나열:

import { readdirSync } from 'fs';

readdirSync(new URL('./', import.meta.url)).forEach((dirContent) => {
  console.log(dirContent);
});

참고: 이 예제에서는 복사 및 실행을 쉽게 하기 위해 동기화 기능을 사용했습니다.

로그이와 한 로그목적이라면 내에서는 이 필요하지 . 이 작업은 3번째로 수행해야 합니다.ESMODULES어느 것에도 의존하지 않는 것은 완전히 가능합니다.__filename 둘 다.__dirname with 터부로원들자와의종토▁resources.new URL이미 해결한 상태에서.


다음과 같은 것을 사용하는 데 관심이 있다면 참고하십시오.require스크립트의 에는 전적인시메스인절의경필대때수다있사습니용할요략할로가크트간립에▁from▁at▁use다▁you있▁can▁path니습,를 사용할 수 있습니다.module.createRequire(filename) + 와 (Node.js v12.2.0 + 파일 이름)의 import.meta.url현재 스크립트 수준이 아닌 다른 수준에서 스크립트를 로드하는 것이 이미 필요하지 않기 때문입니다.__dirname를 한 예import.meta.url와 함께module.createRequire:

import { createRequire } from 'module';

const require = createRequire(import.meta.url);

// foo-bar.js is a CommonJS module.
const fooBar = require('./foo-bar');

fooBar();

에서 foo-bar.js:

module.exports = () => {
    console.log('hello world!');
};

다음 중 "ECMAScript 모듈" 없이 사용하는 것과 유사합니다.

const fooBar = require('./foo-bar');

이러한 변수들을 노출시키는 것에 대한 제안들이 있었습니다.import.meta하지만 지금은 제가 여기서 찾은 엉터리 해결책이 필요합니다.

// expose.js
module.exports = {__dirname};

// use.mjs
import expose from './expose.js';
const {__dirname} = expose;

사용:

import path from 'path';

const __dirname = path.resolve(path.dirname(decodeURI(new URL(import.meta.url).pathname)));

decodeURI중요했습니다. 테스트 시스템의 경로 내에서 사용된 공간 및 기타 항목입니다.

path.resolve()상대 URL을 처리합니다.

편집:

윈도우를 하기 위한 supportwindow (창문)/C:/...=>C:/...):

import path from 'path';

const __dirname = (() => {let x = path.dirname(decodeURI(new URL(import.meta.url).pathname)); return path.resolve( (process.platform == "win32") ? x.substr(1) : x ); })();

현재 스크립트 dirname을 반환할 이 모듈 es-dirname을 만들었습니다.

import dirname from 'es-dirname'

console.log(dirname())

Windows와 Linux에서 CommonJs 스크립트와 ES 모듈 모두에서 작동합니다.

내 프로젝트에서 스크립트가 지금까지 작동했지만 다른 경우에는 실패할 수 있기 때문에 오류가 발생하면 문제를 엽니다.이러한 이유로 프로덕션 환경에서는 사용하지 마십시오.Node.js 팀이 가까운 미래에 강력한 방법을 발표할 것이라고 확신하기 때문에 이는 임시 솔루션입니다.

import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);


// do not use the following code which is bad for CJK characters
const __filename = new URL('', import.meta.url).pathname;

답변은 사례 POSIX)는 마십시오. " " " " " (Windows POSIX) "/ " " (Windows POSIX) "/" " 를 제외하고는 사용할 수 없습니다.__dirname또는__filename그리고 이런 종류의 코드를 어디에서나 반복하는 것은 좀 장황합니다.

import { dirname, join } from 'path'
import { fileURLToPath } from 'url'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

const somePath = join(__dirname, '../some-dir-or-some-file')

저는 이러한 반복적인 작업을 돕기 위해 esm-path라는 NPM 패키지를 출판했습니다. 다른 사람들에게도 유용할 수 있기를 바랍니다.

문서화되어 있지만 사용 방법은 다음과 같습니다.

import { getAbsolutePath } from 'esm-path'

const currentDirectoryPath = getAbsolutePath(import.meta.url)
console.log(currentDirectoryPath)

const parentDirectoryPath = getAbsolutePath(import.meta.url, '..')
console.log(parentDirectoryPath)

// Adapt the relative path to your case
const packageJsonFilePath = getAbsolutePath(import.meta.url, '../package.json')
console.log(packageJsonFilePath)

// Adapt the relative path to your case
const packageJsonFilePath = getAbsolutePath(import.meta.url, '..' , 'package.json')
console.log(packageJsonFilePath)
import path from 'path';
const __dirname = path.join(path.dirname(decodeURI(new URL(import.meta.url).pathname))).replace(/^\\([A-Z]:\\)/, "$1");

Windows에서 할 수 있습니다 (교체으)로 인해 플랫폼에서도 합니다.path.join윈도우즈에서만 백슬래시 구분 기호 반환)

path.resolve() 메서드를 사용합니다.

import { resolve } from 'path';

app.use('/public/uploads', express.static(resolve('public', 'uploads')))

가 경가다음시로작이로옵사용다로 에 이합니다.file://그 부분만 제거하면 됩니다.

const __filename = import.meta.url.slice(7);
const __dirname = import.meta.url.slice(7, import.meta.url.lastIndexOf("/"));

Geoff가 지적했듯이 다음 코드는 모듈의 경로가 아니라 작업 디렉터리를 반환합니다.

import path from 'path';
const __dirname = path.resolve();

와 함께 작동합니다.--experimental-modules

프로젝트 루트에 root-syslogname.js라는 파일을 생성합니다.

import { dirname } from 'path'

const dn = dirname(new URL(import.meta.url).hostname)
const __dirname = process.platform === 'win32' ? dn.substr(1) : dn // remove the leading slash on Windows
export const rootDirname = __dirname

그러면 가져오기만 하면 됩니다.rootDirname프로젝트 루트 폴더에 대한 경로를 지정할 수 있습니다.

그 외에도 루돌프 그뢰링의 대답도 맞습니다.

글로벌 사용에 동의하든 반대하든, 저는 이것이 기존 코드를 기억하고 리팩터링하는 가장 쉬운 방법이라는 것을 알게 되었습니다.

코드 실행의 초기 단계에 위치합니다.

import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';

global.___filename = (path) => {
  return fileURLToPath(path);
};

global.___dirname = (path) => {
  return dirname(global.___filename(path));
};

그런 다음 필요한 파일에서 dirname 또는 filename:

___filename(import.meta.url)
___dirname(import.meta.url)

물론 매크로가 있다면 import.meta.url을 전달할 필요가 없을 것입니다. 아마도 개선 사항이 있을 것입니다.

다른 선택지

import {createRequire} from 'module'; // need node v12.2.0

const require = createRequire(import.meta.url);
const __dirname = require.resolve.paths('.')[0];

은 의스사수있다니에서 할 수 .new Error()오류를 발생시킬 필요가 없으며 프로그램 실행도 중지되지 않습니다.스택의 첫 번째 줄은 항상 오류와 메시지이며, 두 번째 줄은 오류가 발생한 파일입니다.

파일에 메소드이기 에, 이 메소드의 getDirname()호출은 실제로 오류 스택의 세 번째 줄입니다.

export const getDirname = () => {
    // get the stack
    const { stack } = new Error();
    // get the third line (the original invoker)
    const invokeFileLine = stack.split(`\n`)[2];
    // match the file URL from file://(.+)/ and get the first capturing group
    //     the (.+) is a greedy quantifier and will make the RegExp expand to the largest match
    const __dirname = invokeFileLine.match(/file:\/\/(.+)\//)[1];
    return __dirname;
};

저는 또한 NPM에 cross-dirname이라는 패키지를 게시했습니다.es-dirname패키지는 Node.js(ESM 및 CJS), Deno 및 GJS를 사용하여 테스트됩니다.

예:

import dirname from 'cross-dirname'

console.log(dirname())

common-es 패키지는 다음과 같이 정확하게 사용할 수 있습니다.

npm i common-es

사용.

// # myProjectFile.js or myProjectfile.ts

import { getGlobals } from 'common-es'
const { __dirname, __filename } = getGlobals(import.meta.url)
// now you can use __dirname or file name normally as you would do in commonjs

이 이상한 구문에 익숙하지 않은 경우 MDN에서 이 참조를 읽어 보십시오.

나는 다음을 포함하는 1개의 파일 const.js를 만들었습니다:

Object.assign(global, {
    __dirname: __dirname,
    __filename: __filename,
});

그리고나서

import './const.js';
console.log(__dirname);

Get catch-all 문제가 해결되어 해결되었습니다.

구문: my server.js

const express = required ";

const path = required"path';

__proxyname = path.proxy;

const app = express app;

app.get('/*), 함수(req, res) {res.sendFile(path.join(__dirname, '//public/index.html'), 함수(err) {if(err) {res.status(500).send(err) }}}

process.cwd()

설명서에서:

process.cwd()method는 Node.js 프로세스의 현재 작업 디렉터리를 반환합니다.

언급URL : https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules

반응형