Tên nhập biến ES6 trong node.js?


108

có thể nhập một cái gì đó vào mô-đun cung cấp tên biến trong khi sử dụng ES6 nhập?

Tức là tôi muốn nhập một số mô-đun trong thời gian chạy tùy thuộc vào các giá trị được cung cấp trong cấu hình:

import something from './utils/' + variableName;

1
@Bigood có, trình biên dịch ném lên và Webstorm cũng cho thấy một lỗi
Vytautas Butkus

Câu trả lời:


67

Không phải với importtuyên bố. importexportđược định nghĩa theo cách có thể phân tích tĩnh, vì vậy chúng không thể phụ thuộc vào thông tin thời gian chạy.

Bạn đang tìm kiếm API trình tải (polyfill) , nhưng tôi hơi không rõ về trạng thái của đặc điểm kỹ thuật:

System.import('./utils/' + variableName).then(function(m) {
  console.log(m);
});

3
tôi có cần "yêu cầu" Hệ thống không? Nó không phải trên phạm vi toàn cầu .. Ps Tôi đang sử dụng js babel
Vytautas Butkus

Nó chưa được triển khai ở bất kỳ đâu AFAIK. Bạn phải sử dụng polyfill từ liên kết.
Felix Kling

1
Chỉ cần kiểm tra, nó kinda làm việc (cố gắng load file) nhưng sau đó messes lên đường cho các module khác ... Quá xấu nó không được hỗ trợ natively ..
Vytautas Butkus

3
Đây vẫn là một vấn đề? Tôi cần tải các mô-đun ES6 một cách di động nhưng tôi đã không thành công ..
calbertts

26

Ngoài câu trả lời của Felix , tôi sẽ lưu ý rõ ràng rằng điều này hiện không được phép trong ngữ pháp ECMAScript 6 :

Khai báo nhập khẩu :

  • nhập ImportClause FromClause;

  • nhập ModuleSpecifier;

FromClause :

  • từ ModuleSpecifier

ModuleSpecifier :

  • Chuỗi chữ

Một ModuleSpecifier chỉ có thể là một StringLiteral , không bất kỳ loại khác của biểu thức như một AdditiveExpression .


2
Thật tiếc điều này không được mở rộng để bao gồm const string literals. Chúng có thể phân tích tĩnh, phải không? Nó sẽ làm cho việc sử dụng lại vị trí của một phụ thuộc là một khả năng. (ví dụ: nhập một mẫu và có sẵn cả mẫu và vị trí của mẫu).
nicodemus13

26

Trong khi đây thực sự không phải là nhập động (ví dụ: trong trường hợp của tôi, tất cả các tệp tôi đang nhập bên dưới sẽ được nhập và đóng gói bởi webpack, không được chọn trong thời gian chạy), một mẫu mà tôi đang sử dụng có thể hỗ trợ trong một số trường hợp là :

import Template1 from './Template1.js';
import Template2 from './Template2.js';

const templates = {
  Template1,
  Template2
};

export function getTemplate (name) {
  return templates[name];
}

Hay cách khác:

// index.js
export { default as Template1 } from './Template1';
export { default as Template2 } from './Template2';


// OtherComponent.js
import * as templates from './index.js'
...
// handy to be able to fall back to a default!
return templates[name] || templates.Template1;

Tôi không nghĩ mình có thể trở lại tình trạng mặc định một cách dễ dàng với require() , điều này gây ra lỗi nếu tôi cố gắng nhập một đường dẫn mẫu đã xây dựng không tồn tại.

Bạn có thể tìm thấy các ví dụ hay và so sánh giữa request và import tại đây: http://www.2ality.com/2014/09/es6-modules-final.html

Tài liệu tuyệt vời về cách xuất lại từ @iainastacio: http://exploringjs.com/es6/ch_modules.html#sec_all-exporting-styles

Tôi muốn nghe phản hồi về cách tiếp cận này :)


Ủng hộ. Tôi đã sử dụng cách tiếp cận "hoặc cách khác". Hoạt động như một sự quyến rũ cho giải pháp bản địa hóa tùy chỉnh của tôi.
groundh0g


1
Tôi nên nghĩ về điều này. Giải pháp tuyệt vời, bất kể bạn đang nhập mọi thứ bằng cách nào (và ngay cả khi bạn không nhập bất cứ thứ gì). Có một danh sách các mục mà bạn muốn lấy tên hoặc lấy tên, sau này? Đặt chúng trong một đối tượng theo nghĩa đen thay vì một ký tự mảng và để cú pháp đối tượng đảm nhận việc đặt tên chúng dựa trên tên biến / hằng cục bộ của chúng. Nếu bạn cần chúng như một danh sách một lần nữa, chỉ cần làm Object.values(templates).
Andrew Koster

15

Có một đặc điểm kỹ thuật mới được gọi là nhập động cho các mô-đun ES. Về cơ bản, bạn chỉ cần gọi import('./path/file.js')và bạn có thể đi. Hàm trả về một lời hứa, sẽ giải quyết bằng mô-đun nếu quá trình nhập thành công.

async function importModule() {
   try {
      const module = await import('./path/module.js');
   } catch (error) {
      console.error('import failed');
   }
}

Trường hợp sử dụng

Các trường hợp sử dụng bao gồm nhập thành phần dựa trên tuyến đường cho React, Vue, v.v. và khả năng lười tải các mô-đun , một khi chúng được yêu cầu trong thời gian chạy.

Thêm thông tin

Đây là giải thích về Google Developers .

Khả năng tương thích của trình duyệt (tháng 4 năm 2020)

Theo MDN, nó được hỗ trợ bởi mọi trình duyệt lớn hiện tại (ngoại trừ IE) và caniuse.com cho thấy sự hỗ trợ 87% trên thị phần toàn cầu. Một lần nữa không hỗ trợ IE hoặc Edge non-chromium.


bạn có chắc chắn về chỉnh sửa của bạn? đề xuất hiển thị một ví dụ với đường dẫn có thể thay đổi: github.com/tc39/proposal-dynamic-import#example
phil294

@Blauhirn Tôi đã có, nhưng liên kết của bạn cho thấy rõ ràng rằng đó là một khả năng. Mặc dù tôi không biết cách webpack sẽ giải quyết những lần nhập này như thế nào
Nicolai Schmid

Hãy sửa cho tôi nếu tôi sai, nhưng webpack không xử lý những điều này, phải không? Tôi nghĩ rằng đó là điểm của nhập động mà chúng chạy "nguyên trạng" trong trình duyệt.
phil294,

Có, bạn có thể chạy chúng trong trình duyệt. Tuy nhiên, webpack tự động sử dụng các mục nhập để chia ứng dụng của bạn thành nhiều gói cho các phần khác nhau của ứng dụng, chẳng hạn như các tuyến đường. Tôi sử dụng chúng mọi lúc và chúng thực sự hữu ích. Và theo như "xử lý" đi; webpack sẽ vượt qua việc nhập babel, điều này sẽ làm đa dạng tính năng cho các trình duyệt cũ hơn.
Nicolai Schmid

Nói rõ hơn: dynamic import () sẽ hoạt động với các biến và không bắt buộc phải có thể phân tích tĩnh (chắc chắn đó là toàn bộ điểm của 'động'?). Hãy xem câu trả lời của tôi.
Velojet

6

Tôi hiểu câu hỏi được hỏi cụ thể cho ES6 importtrong Node.js, nhưng điều sau có thể giúp những người khác đang tìm kiếm giải pháp chung chung hơn:

let variableName = "es5.js";
const something = require(`./utils/${variableName}`);

Lưu ý nếu bạn đang nhập một mô-đun ES6 và cần truy cập vào quá trình defaultxuất, bạn sẽ cần sử dụng một trong các cách sau:

let variableName = "es6.js";

// Assigning
const defaultMethod = require(`./utils/${variableName}`).default;

// Accessing
const something = require(`./utils/${variableName}`);
something.default();

Bạn cũng có thể sử dụng cấu trúc hủy với cách tiếp cận này có thể thêm quen thuộc về cú pháp với các lần nhập khác của bạn:

// Destructuring 
const { someMethod } = require(`./utils/${variableName}`);    
someMethod();

Thật không may, nếu bạn muốn truy cập defaultcũng như cấu trúc lại, bạn sẽ cần thực hiện việc này theo nhiều bước:

// ES6 Syntax
Import defaultMethod, { someMethod } from "const-path.js";

// Destructuring + default assignment
const something = require(`./utils/${variableName}`);

const defaultMethod = something.default;    
const { someMethod, someOtherMethod } = something;

4

bạn có thể sử dụng ký hiệu không phải ES6 để làm điều đó. Đây là những gì làm việc cho tôi:

let myModule = null;
if (needsToLoadModule) {
  myModule = require('my-module').default;
}

3

Tôi ít thích cú pháp này hơn, nhưng nó hoạt động:
thay vì viết

import memberName from "path" + "fileName"; 
// this will not work!, since "path" + "fileName" need to be string literal

sử dụng cú pháp này:

let memberName = require("path" + "fileName");

1
@UlysseBN Khác biệt theo cách xấu? Hay một cách không thực sự quan trọng?
Sam

@Jacob họ thực sự hoàn toàn khác nhau, vì vậy nó có thể quan trọng tùy thuộc vào những gì bạn đang làm. Cú pháp đầu tiên được đánh giá tĩnh, trong khi cú pháp thứ hai được đánh giá động. Vì vậy, ví dụ: nếu bạn đang sử dụng webpack, sẽ không thực hiện rung cây một cách chính xác với cái thứ hai. Có nhiều điểm khác biệt khác, tôi khuyên bạn nên đọc tài liệu và xem tài liệu nào phù hợp hơn với bạn!
Ulysse BN

@Jacob - Không thực sự quan trọng (trong hầu hết các trường hợp). require()là một phương thức Node.JS để tải tệp, là phiên bản đầu tiên. importcâu lệnh là phiên bản mới hơn, hiện là một phần của cú pháp ngôn ngữ chính thức. Tuy nhiên trong nhiều trường hợp trình duyệt sẽ sử dụng cái trước (sau khoa học). Câu lệnh request cũng sẽ tính tiền cho các tệp của bạn, vì vậy nếu tệp được tải lần thứ 2, tệp sẽ được tải từ bộ nhớ (hiệu suất tốt hơn). Cách nhập có những lợi ích riêng - nếu bạn đang sử dụng WebPack. thì webpack có thể loại bỏ các tham chiếu đã chết (các tập lệnh này sẽ không được tải xuống máy khách).
Gil Epshtain

1

Nhập động () (khả dụng trong Chrome 63+) sẽ thực hiện công việc của bạn. Đây là cách thực hiện:

let variableName = 'test.js';
let utilsPath = './utils/' + variableName;
import(utilsPath).then((module) => { module.something(); });

0

Tôi sẽ làm nó như thế này

function load(filePath) {
     return () => System.import(`${filePath}.js`); 
     // Note: Change .js to your file extension
}

let A = load('./utils/' + variableName)

// Now you can use A in your module

0

./utils/test.js

export default () => {
  doSomething...
}

cuộc gọi từ tệp

const variableName = 'test';
const package = require(`./utils/${variableName}`);
package.default();
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.