Nodejs sửa đổi tệp js

Gần đây, tôi đang thực hiện một dự án phụ, dựa trên việc đọc và thao tác với các tệp để tạo hình thu nhỏ tùy chỉnh cho quay số nhanh của trình duyệt Vivaldi. Tôi đã có thể thực hiện tất cả trong trình duyệt mà không cần xử lý phía máy chủ và tôi muốn chia sẻ với bạn mọi thứ mà tôi đã học được

Hướng dẫn này bao gồm

  • sử dụng objectURL và FileReader để đọc tệp từ hệ thống tệp của người dùng
  • lấy thông tin của một tập tin như. kích thước, loại và nhiều hơn nữa
  • hiển thị bản xem trước của các tệp hình ảnh đã chọn
  • xử lý lỗi và trạng thái tải
  • BẢNG XẾP HẠNG Ở CUỐI
Chọn tệp từ hệ thống tệp

Để cho phép người dùng của bạn chọn một tệp từ thiết bị của họ, trước tiên bạn phải tạo một input với loại tệp

Để thực sự lấy các tệp từ đầu vào này, bạn sẽ cần truy cập thuộc tính files của phần tử đầu vào. Tốt nhất là làm điều đó bằng cách đăng ký một trình lắng nghe sự kiện thay đổi trên phần tử đầu vào. Bằng cách này, một chức năng gọi lại sẽ được gọi mỗi khi người dùng chọn một tệp

Cách bạn làm điều đó sẽ phụ thuộc vào khuôn khổ bạn đang sử dụng. Để làm cho hướng dẫn này được áp dụng rộng rãi nhất có thể, chúng tôi sẽ sử dụng vanilla JS

Kết quả selectFile là một đối tượng File

Thuộc tính của tập tin

Đầu vào tệp cung cấp cho chúng tôi File đối tượng, vì vậy ngoài nội dung của tệp, chúng tôi có quyền truy cập vào một số thông tin bổ sung, chẳng hạn như

  • name - tên tệp, bao gồm cả phần mở rộng nhưng không có đường dẫn (e. g. "cat_photo. png")
  • size - kích thước của tệp tính bằng byte. Để có được kích thước ở định dạng dễ đọc hơn của con người, bạn có thể sử dụng thư viện như kích thước tệp hoặc byte. Đối với các trường hợp sử dụng đơn giản, bạn thậm chí có thể viết logic chuyển đổi của riêng mình
  • type - loại MIME của tệp (e. g. "văn bản/đơn giản", "hình ảnh/png")
  • lastModified - ngày sửa đổi cuối cùng của tệp, được biểu thị bằng số mili giây kể từ Kỷ nguyên Unix (01/01/1970 lúc nửa đêm). Bạn có thể sử dụng hàm tạo Ngày để chuyển đổi dấu thời gian này thành đối tượng Date javascript hữu ích hơn

Files cũng có hai thuộc tính khác. files0 và files1, cái đầu tiên không được dùng nữa và cái còn lại không chuẩn, vì vậy có lẽ bạn nên tránh sử dụng chúng. Hãy nhớ rằng tất cả các thuộc tính này là chỉ đọc

Tập tin và đốm màu

Ngoài File, javascript còn có một cách khác để biểu diễn các tệp, được gọi là files3

files3 chứa dữ liệu của tệp chung, cùng với thông tin về kích thước và loại tệp. File thực ra chỉ là một files3 chuyên biệt hơn, được sử dụng để biểu thị các tệp cụ thể trong hệ thống tệp của người dùng. Nó kế thừa tất cả các phương thức và thuộc tính của Blob, đồng thời chứa một số thông tin bổ sung về tên tệp và ngày sửa đổi lần cuối

Hai cái này về cơ bản có thể hoán đổi cho nhau và bạn có thể sử dụng cái này ở hầu hết mọi nơi bạn có thể sử dụng cái kia. Tuy nhiên, nếu bạn thực sự cần chuyển đổi chúng, bạn có thể làm như vậy bằng cách sử dụng hàm tạo của loại khác

Đọc nội dung của tập tin

Được rồi, vậy là chúng ta đã biết cách chọn và lấy thông tin về các tệp, nhưng làm cách nào để chúng ta thực sự đọc nội dung bên trong chúng? . Đối với mục đích của bài viết này, chúng tôi sẽ chỉ tập trung vào các tệp hình ảnh và văn bản

Phương pháp linh hoạt và được hỗ trợ tốt nhất để đọc nội dung của tệp là API FileReader. Đó là một API hướng sự kiện, vì vậy thay vì chỉ gọi một hàm và lấy nội dung của tệp, chúng ta phải thực hiện thêm một số bước

Hãy bắt đầu với việc đọc một tệp văn bản

  1. Trước tiên, chúng tôi lấy phần tử đầu vào tệp và đăng ký trình xử lý sự kiện thay đổi trên phần tử đó bằng cách gán hàm gọi lại cho thuộc tính files7 của nó
  2. Chúng tôi nhận được tập tin đã chọn
  3. Chúng tôi kiểm tra xem một tệp có thực sự được chọn hay không và nếu không, (điều này có thể xảy ra chẳng hạn nếu người dùng nhấp vào 'hủy' trong cửa sổ lựa chọn), chúng tôi sẽ thoát khỏi chức năng
  4. Tiếp theo, chúng tôi tạo một phiên bản của FileReader
  5. Sau đó, chúng tôi đăng ký bất kỳ trình xử lý sự kiện nào mà chúng tôi có thể cần. Để truy cập nội dung tệp, chúng tôi chỉ thực sự cần sự kiện tải, sự kiện này sẽ kích hoạt khi thao tác đọc kết thúc thành công. Tuy nhiên, bạn cũng nên đăng ký một trình xử lý lỗi. Dưới đây là danh sách đầy đủ các sự kiện có thể xảy ra trong bài viết, cùng với một số mẹo xử lý lỗi, vì vậy hãy tiếp tục đọc 😉
  6. Sau khi tất cả các trình xử lý sự kiện được đăng ký, chúng tôi bắt đầu thao tác đọc bằng cách gọi một trong các phương thức readAs, trong trường hợp này là files8
  7. Sau khi thao tác đọc kết thúc, nội dung tệp sẽ có sẵn trong thuộc tính files9 mà chúng ta có thể truy cập bên trong trình xử lý sự kiện tải (hàm gọi lại File0)

Mẹo nhanh. Bạn có thể truy cập trình đọc bên trong trình xử lý sự kiện theo nhiều cách. File1. Hãy nhớ rằng File2 không có sẵn trong arrow functions

Xử lý lỗi

Trong trường hợp có lỗi, trình xử lý sự kiện lỗi được gọi và bạn có thể tìm thấy đối tượng Lỗi trong File3. Mã lỗi có thể là

  • File4 - không tìm thấy tệp
  • File5 - không thể đọc tệp
  • File6 - đã xảy ra sự cố bảo mật
  • File7 - ​​bị ném khi File8 được gọi trong khi không có thao tác đọc nào đang diễn ra

Hầu hết thời gian không cần phân biệt giữa các loại lỗi này, có thể ngoại trừ File9 nói chung là vô hại và có thể bỏ qua

Trạng thái sẵn sàng

Thao tác đọc không đồng bộ, vì vậy đừng thử truy cập vào files9 ngay sau lệnh gọi readAs. Nếu bạn thực sự cần kiểm tra giá trị files9 bên ngoài trình xử lý sự kiện tải, trước tiên hãy đảm bảo kiểm tra giá trị của File2, đây sẽ là một trong 3 giá trị

  • File3 - Trình đọc đã được tạo, nhưng chưa có phương thức readAs nào được gọi. (TRỐNG RỖNG)
  • File4 - Một trong các phương thức readAs đã được gọi. Thao tác đọc đang diễn ra và chưa có lỗi nào xảy ra. (ĐANG TẢI)
  • File5 - Hoạt động đã kết thúc. Điều này có thể có nghĩa là một trong ba điều. ________ đã được đọc thành công, đã xảy ra lỗi đọc hoặc File8 đã được gọi và thao tác đã bị hủy. (XONG)

Thuộc tính files9 sẽ chỉ được điền trong trường hợp thao tác đọc thành công. Trong tất cả các trường hợp khác, nó sẽ là File9

Điều tương tự cũng áp dụng cho File3 nên được truy cập bên trong trình xử lý sự kiện lỗi

Các loại sự kiện FileReader

Chúng ta đã khám phá hai loại sự kiện đọc phổ biến nhất, giờ hãy nhanh chóng tìm hiểu phần còn lại. FileReader có sáu loại sự kiện

  • name1 - được kích hoạt khi hoàn tất thành công thao tác đọc
  • name2 - được kích hoạt khi thao tác đọc gặp lỗi
  • name3 - được kích hoạt định kỳ trong khi File hoặc files3 đang được đọc và chứa thông tin về tiến trình của hoạt động. Có thể được sử dụng để triển khai các thanh tải
  • name6 - được kích hoạt khi thao tác đọc bị hủy, tôi. e. khi File8 được gọi
  • name8 - được kích hoạt khi thao tác đọc bắt đầu
  • name9 - được kích hoạt khi thao tác đọc kết thúc, bất kể thao tác đó thành công hay thất bại

Bạn có thể nhận thấy rằng các sự kiện FileReader hoạt động tương tự như các sự kiện DOM thông thường. Tôi thấy rằng suy nghĩ về chúng như vậy sẽ giúp hiểu bản chất phi tuyến tính, không đồng bộ của chúng dễ dàng hơn rất nhiều

💡 Chú thích bên lề. Giống như với các sự kiện DOM, có thể đăng ký trình xử lý sự kiện bằng cách sử dụng size0 hoặc bằng cách gán hàm gọi lại cho thuộc tính "oneeventname" của trình đọc

Bãi. chữ()

Cũng cần lưu ý rằng để đọc các tệp văn bản, tồn tại một phương pháp mới hơn và đơn giản hơn. size1. Hãy nhớ rằng File chỉ là một files3 với một số chức năng bổ sung, vì vậy nó kế thừa tất cả các phương thức của Blob, bao gồm cả phương thức này. Điều này có nghĩa là bạn có thể sử dụng phương pháp này trên cả Blobs và Files

Nó không trông đẹp hơn sao? . API này khá mới và hỗ trợ trình duyệt vẫn còn khá kém

Làm việc với hình ảnh

Bây giờ chúng ta đã biết cách đọc tệp văn bản, hãy chuyển sang phần thú vị hơn. hình ảnh. Để minh họa chủ đề này, chúng ta sẽ xây dựng một bản xem trước đơn giản của hình ảnh đã chọn

Loại tập tin

Trước tiên, hãy đảm bảo rằng tệp đã chọn thực sự là một hình ảnh. Chúng ta có thể làm điều đó với sự trợ giúp của thuộc tính size4

Thuộc tính size4, cho phép bạn chỉ định loại tệp nào người dùng sẽ được phép chọn. Nó sử dụng một danh sách xác định loại tệp duy nhất được phân tách bằng dấu phẩy. Mỗi công cụ xác định loại có thể ở một trong các định dạng sau

  • Phần mở rộng tên tệp không phân biệt chữ hoa chữ thường, bắt đầu bằng dấu chấm (“. ") nhân vật. Ví dụ. ________ 56, ________ 57, ________ 58, ________ 59
  • Một loại MIME, ví dụ. ________ 60, ________ 61, ________ 62, ________ 63
  • type4 có nghĩa là "bất kỳ tệp hình ảnh nào"
  • type5 có nghĩa là "bất kỳ tệp âm thanh nào"
  • type6 có nghĩa là "bất kỳ tệp video nào"

Bạn có thể trộn và kết hợp những thứ này để phù hợp với trường hợp sử dụng cụ thể của mình

Xác thực HTML không hoàn hảo mặc dù. Ví dụ: trên Windows, nó sẽ chỉ ẩn các tệp không phù hợp với tiêu chí của bạn, nhưng bạn vẫn có thể chọn “Tất cả tệp (*. *)” hoặc sử dụng tính năng kéo và thả để chọn bất kỳ tệp nào bạn muốn. Tất cả điều này có nghĩa là bạn cũng nên kiểm tra loại tệp bên trong mã javascript của mình

Hoặc bạn có thể thiết lập các luồng xử lý riêng cho các loại tệp khác nhau

Thật không may, type7 và type8 không hoạt động trong các trình duyệt cũ hơn như Internet Explorer, vì vậy nếu bạn cần hỗ trợ chúng, bạn có thể muốn xem xét một số giải pháp thay thế hoặc polyfill

Ngoài ra, hãy nhớ rằng “bất kỳ tệp hình ảnh nào” sẽ khớp (trong số những tệp khác)

  • hình ảnh có hỗ trợ trình duyệt kém hoàn hảo, như type9
  • hình ảnh có độ trong suốt, như lastModified0
  • hình ảnh hoạt hình, như của lastModified1

Vì vậy, hãy đảm bảo rằng bạn hỗ trợ tất cả các chức năng này hoặc chỉ xác định rõ ràng những loại bạn dự định hỗ trợ

URL dữ liệu & URL đối tượng

Để hiển thị một hình ảnh đã chọn, chúng tôi sẽ cần một HTML img và một URL cho thuộc tính lastModified2. Có hai cách khác nhau để thể hiện tệp hình ảnh dưới dạng URL. một dataURL và objectURL. Có một số khác biệt quan trọng giữa hai loại này, vì vậy hãy nhanh chóng lướt qua chúng

URL dữ liệu

Đó là kết quả của lastModified3. Đó là một chuỗi chứa loại tệp và dữ liệu nhị phân thực tế của tệp, được mã hóa bằng base64

Định dạng của nó có thể thay đổi một chút tùy thuộc vào loại dữ liệu mà nó đại diện, nhưng đối với hầu hết các tệp, nó trông như thế này. lastModified4, trong đó lastModified5 là loại MIME và lastModified6 là tệp được mã hóa base64

Bởi vì nó thực sự chứa dữ liệu của tệp nên nó có thể được sử dụng ở bất cứ đâu sau khi được tạo mà không cần tệp gốc. Tuyệt đấy

URL đối tượng

Còn được gọi là URL blob. Đó là kết quả của lastModified7. Nó là một API mới hơn, nhưng vẫn được hỗ trợ khá tốt. Tuy nhiên, nó sẽ không hoạt động trong IE phiên bản 9 trở xuống

Nó nhanh hơn và ngắn gọn hơn lastModified8 nhưng nó đi kèm với những vấn đề đau đầu và hạn chế của riêng nó. Ngược lại với dataURL, nó không chứa bất kỳ tệp dữ liệu nào. Nó chỉ là một tham chiếu đến một tập tin. Một điểm khác biệt quan trọng nữa là lastModified7 đồng bộ

ObjectURL phải được thu hồi khi không còn cần thiết. Trình duyệt sẽ tự động thực hiện khi tài liệu được tải xuống, tuy nhiên để đạt hiệu suất tối ưu và sử dụng bộ nhớ, bạn không nên dựa vào hành vi đó, đặc biệt là trong các ứng dụng lớn có nhiều URL đối tượng. Thay vào đó, bạn nên gọi rõ ràng Date0 khi url không còn cần thiết, ví dụ như trong trình xử lý sự kiện Date1, chúng ta sẽ thảo luận sau

💡 Chú thích bên lề. để lấy dữ liệu tệp được mã hóa base64 từ một dataURL, chỉ cần trích xuất một phần của chuỗi sau dấu phẩy, như thế này. Date2

Hiển thị hình ảnh đã chọn

Hầu hết các URL đối tượng và URL dữ liệu có thể được sử dụng thay thế cho nhau, nhưng chúng đều có điểm mạnh và điểm yếu riêng. Điều này có nghĩa là bạn có thể nên tìm hiểu cả hai và chọn cái nào sẽ sử dụng trong từng trường hợp cụ thể. Hãy xem xét các ví dụ về cả hai, để hiểu rõ hơn về cách thức hoạt động của từng loại

Sử dụng FileReader & dataURL

  1. Chúng tôi đăng ký một trình lắng nghe sự kiện thay đổi trên đầu vào tệp
  2. Bên trong cuộc gọi lại files7, chúng tôi lấy tệp đã chọn và tạo một phiên bản của lastModified8
  3. Chúng tôi đăng ký một trình lắng nghe sự kiện tải trên đầu đọc
  4. Bên trong cuộc gọi lại Date5, chúng tôi tạo một phần tử hình ảnh mới,
  5. Sau đó, chúng tôi lấy dataURL từ files9 (hãy nhớ rằng, Date7 trỏ đến Date8) và gán nó cho thuộc tính lastModified2 giống như trong HTML
  6. Sau khi thuộc tính src được đặt, chúng tôi sẽ nối toàn bộ phần tử File0 vào DOM với tư cách là phần tử con của previewContainer của chúng tôi. (Thực ra chúng ta có thể vừa tạo thẻ File0 trong HTML và cập nhật thuộc tính src trong javascript, nhưng làm theo cách này thực sự chuẩn bị cho chúng ta làm việc với nhiều hình ảnh cùng một lúc và thao tác với hình ảnh trong một File2)
  7. Khi mọi thứ đã được thiết lập, chúng tôi bắt đầu thao tác đọc bằng cách sử dụng File3, thao tác này sẽ kích hoạt trình nghe Date5 của chúng tôi khi đọc xong tệp

Sử dụng objectURL

  1. Chúng tôi đăng ký một trình lắng nghe sự kiện thay đổi trên đầu vào tệp
  2. Bên trong cuộc gọi lại files7, chúng tôi lấy tệp đã chọn và tạo một phần tử hình ảnh mới
  3. Chúng tôi đăng ký một trình xử lý sự kiện tải trên hình ảnh
  4. Bên trong cuộc gọi lại Date5, Date0 sẽ thu hồi objectURL sau khi hình ảnh được tải đầy đủ và url không còn cần thiết nữa. Bước này không cần thiết, nhưng rất khuyến khích. Hãy nhớ rằng nếu sau này bạn cần url đó ở một nơi khác, thì bạn chưa nên thu hồi nó
  5. Khi hình ảnh được tải đầy đủ, chúng tôi sẽ không cần objectURL nữa. Vì vậy, bên trong cuộc gọi lại Date5, chúng tôi thu hồi url đó. Để làm điều đó, chúng tôi chuyển nó làm đối số cho Date0. Chúng ta có thể lấy url trực tiếp từ thuộc tính src của hình ảnh
  6. Chúng tôi tạo objectURL, bằng cách chuyển tệp đã chọn làm đối số cho lastModified7 và gán nó cho thuộc tính lastModified2
  7. Sau khi thuộc tính src được đặt, chúng tôi sẽ nối toàn bộ phần tử File0 vào DOM với tư cách là phần tử con của previewContainer của chúng tôi

💡 Chú thích bên lề. Ở những nơi khác, bạn có thể thấy các hình ảnh được tạo bằng cách sử dụng hàm tạo Hình ảnh i. e. files03. Hầu hết thời gian nó tương đương với files04 và tôi chưa bao giờ gặp vấn đề gì với cả hai. Tuy nhiên, có thể có một số trường hợp cạnh (được mô tả trong chuỗi StackOverflow này), điều này dường như làm cho trường hợp sau trở thành một tùy chọn đáng tin cậy hơn

FileList

Trước khi chúng tôi chuyển sang đọc nhiều tệp, hãy làm rõ một số thứ. Thuộc tính files không thực sự là một files06, mặc dù nó trông giống như một 😮. Đó là một kiểu dữ liệu đặc biệt của files07. Điều này có nghĩa là nó không có quyền truy cập vào các phương thức mảng thông thường (như files08, files09, files10), do đó, để lặp lại danh sách, bạn sẽ phải sáng tạo. Tôi sẽ chỉ cho bạn một vài cách khác nhau để làm điều này, nhưng nếu bạn muốn biết thêm, hãy xem chủ đề StackOverflow này

Bạn cũng có thể nhận thấy rằng mặc dù chúng tôi chỉ làm việc với một tệp duy nhất (cho đến bây giờ), chúng tôi luôn phải viết files11. Đó là bởi vì bất kể thuộc tính files12 có được thiết lập hay không, thì files13 luôn là một files07. Điều này có nghĩa là ngay cả khi đầu vào chỉ chấp nhận một tệp, bạn vẫn phải cung cấp chỉ mục, trong trường hợp chỉ có một mục là 0

💡 Chú thích bên lề. Theo dự thảo làm việc của w3c, files07 có thể được thay thế bằng một files06 thông thường trong tương lai gần. Bắt chéo ngón tay 🤞

Giao diện FileList nên được coi là "có nguy cơ" vì xu hướng chung trên Nền tảng web là thay thế các giao diện đó bằng đối tượng nền tảng Array trong ECMAScript [ECMA-262]. Đặc biệt, điều này có nghĩa là cú pháp sắp xếp filelist. mục (0) có nguy cơ;

Đọc nhiều tệp

Mặc định file input chỉ cho phép ta chọn 1 file duy nhất. Để cho phép chọn nhiều tệp cùng lúc, hãy thêm thuộc tính files12 vào phần tử html

Trong ví dụ này, tôi sẽ sử dụng lastModified8 vì nó không đồng bộ và sẽ không chặn giao diện người dùng khi xử lý nhiều tệp. Nhưng nếu bạn muốn, bạn có thể sử dụng objectURL để thay thế và trong hầu hết các trường hợp, bạn sẽ ổn thôi

Bởi vì chúng ta đã làm hầu hết điều này trước đây, nên tôi sẽ chỉ sử dụng nhận xét để gọi ra các phần quan trọng của mã. Nếu bạn đã bỏ qua các phần trước, tôi khuyên bạn nên quay lại và bắt kịp, tôi sẽ đợi 😉⏳

Như bạn có thể thấy, chúng tôi tạo một phiên bản lastModified8 riêng biệt cho mọi tệp. Điều tương tự có thể đạt được bằng cách gọi files20 bên trong trình xử lý sự kiện name9, nhưng cách này thực hiện công việc và dù sao cũng có thể nhanh hơn

cheatsheet

Đây là một bản tóm tắt về toàn bộ quy trình xử lý tệp, bao gồm tất cả các lớp và phương thức liên quan

Cảm ơn vì đã đọc

Nếu có điều gì đó không rõ ràng hoặc bạn muốn tôi mở rộng về chủ đề nào đó, hãy cho tôi biết trong phần nhận xét

Các bài viết thú vị khác

Tìm hiểu tất cả 8 thuộc tính CSS nền trong 5 phút

Giới thiệu nhanh nhưng đầy đủ về thuộc tính nền CSS

hadrysmateusz. Trung bình. com

Hướng dẫn đầy đủ về CSS Gradients

Chuyển màu đang quay trở lại, hãy đảm bảo bạn biết cách sử dụng chúng

hadrysmateusz. Trung bình. com

20 bộ chọn CSS bạn cần biết

Đảm bảo bạn biết các Bộ chọn CSS quan trọng này

Trung bình. com

Ngoài ra, nếu bạn là một người hâm mộ Vivaldi như tôi, hãy xem Trình tạo hình thu nhỏ Vivaldi của tôi, đó là một công cụ miễn phí do tôi tạo ra vì tôi đã quá mệt mỏi với việc tạo hình thu nhỏ theo cách thủ công. Nó sử dụng rất nhiều khái niệm từ bài đăng này và bạn có thể xem toàn bộ mã nguồn trên GitHub

Làm cách nào để chỉnh sửa tệp JavaScript?

Sau khi tải hoàn toàn một trang web, nhấn phím F12 để mở công cụ dành cho nhà phát triển, sau đó mở tab 'Nguồn'. Bây giờ hãy mở bất kỳ tệp Javascript nào được tải trên trình duyệt và bạn có thể chỉnh sửa trực tiếp tệp đó bằng cách nhấp vào bất kỳ đâu trong tệp đó. Sau khi sửa xong nhấn Ctrl+S để lưu thay đổi

JavaScript có thể chỉnh sửa tệp văn bản không?

Bạn có thể đọc dữ liệu trong tệp văn bản, sửa đổi dữ liệu đó trong JavaScript phía máy khách (không có Nút), sau đó xuất và lưu lại . Tuy nhiên, nó yêu cầu sự tương tác của người dùng.

Làm cách nào để đọc tệp js trong JavaScript?

Để đọc tệp, sử dụng FileReader , cho phép bạn đọc nội dung của đối tượng Tệp vào bộ nhớ. Bạn có thể hướng dẫn FileReader đọc tệp dưới dạng bộ đệm mảng, URL dữ liệu hoặc văn bản. // Kiểm tra xem file có phải là ảnh không.

Cách tạo một nút. tập tin js?

Tạo ứng dụng web NodeJS đầu tiên của bạn bằng Express .
Mở dòng lệnh của bạn (Command Prompt, Powershell hoặc bất cứ thứ gì bạn thích)
Tạo một thư mục dự án mới. mkdir ExpressProjects và nhập thư mục đó. cd ExpressProjects
Sử dụng Express để tạo mẫu dự án HelloWorld. trình tạo nhanh npx HelloWorld --view=pug