Tôi còn nhớ rất rõ một câu hỏi từ thời còn đang thực tập với anh hướng dẫn. Anh là một Senior phụ trách kèm cặp tôi lúc đó. Khi thấy anh đang làm việc, tôi thốt lên: "Uầy, anh code cả Java ạ?". Anh không nói gì chỉ khẽ cười và tiếp tục công việc của mình. Thế giới lập trình với tôi lúc đó thật nhỏ bé, nếu không có kiến thức và kinh nghiệm, mọi thứ đối với mình thật lạ lẫm, làm sao mà một người có thể biết nhiều thứ đến như vậy? Còn nếu không đủ trải nghiệm, thì mình bị giới hạn cách nhìn nhận sự việc trong tầm hiểu biết.
Là một lập trình viên Node.js lâu năm. Lúc đầu tôi rất thích JavaScript cũng như Node vì tính phóng khoáng của nó. Không có quy tắc, bất kỳ sự sáng tạo nào đều được chấp nhận. Ấy thế mà dần dần mình lại sợ chính những thứ mà hồi đầu lấy làm tung hô. JavaScript quá đơn giản để phức tạp.
Cách đây vài năm, lần đầu nghe đến cái tên Deno. Đặc biệt còn do tác giả của Node - Ryan Dahl chế tạo ra thì nó đã thu hút sự chú ý của tôi. Trong một bài phát biểu 10 điều mà Ryan cảm thấy hối hận vì đã làm với Node.js (Mà tôi đã có một bài viết rút gọn xuống). Anh luôn cảm thấy day dứt vì sự phổ biến của Node.js và mong muốn làm được điều gì đó hy vọng đưa JavaScript về lại đúng với con đường mà nó nên đi. Deno ra đời như một đứa con khắc phục hết điểm yếu của cha nó. Nhưng có vẻ như nhiều người không mặn mà với Deno cho lắm. Thậm chí ngay từ đầu đã có rất nhiều câu hỏi rằng liệu ai mới là người dùng Deno trong môi trường sản xuất (production) chứ!?
Tôi cũng vậy, không thực sự quan tâm đến sự có mặt của Deno cho lắm, có chăng chỉ là sự tò mò mỗi khi thương hiệu ra mắt một sản phẩm mới. Một phần do công việc sử dụng Node.js là chính, vậy sao phải sang Deno làm gì? Giả sử có tìm hiểu đi chăng nữa thì cũng nhanh chóng quên đi hoặc chán nản vì không có dự án nào để làm. Trong lúc đập đi xây lại blog thì cái tên Fresh bỗng xuất hiện thu hút sự chú ý của tôi. Nó hội tụ rất nhiều tiêu chí mà tôi cần lúc đó. Fresh được xây dựng dựa trên Deno, nói vậy tức là cần biết Deno trước khi làm được Fresh. Nhưng bây giờ học thì liệu có kịp không? Trong khi đang cần xây dựng lại trang web nhanh nhất có thể.
Nghĩ thế nhưng cuối cùng tôi vẫn bắt tay vào làm. Chỉ mất một thời gian ngắn ban đầu để làm quen với cú pháp mới, thành phần mới. Ngoài những điều đó ra thì về cơ bản giữa Deno và Node không khác nhau là mấy. Vì thế bài viết ngày hôm nay tôi sẽ điểm lại một số khái niệm cơ bản bên Deno mà tương tự như Node.js. Qua đó giúp bạn đọc nắm bắt được sự tương đồng nếu có "quay xe" sang sử dụng công cụ mới mẻ này.
Nếu như với Node, chúng ta cần tích hợp thêm TypeScript bằng cách thủ công, hoặc sử dụng Framework đã được tích hợp sẵn TypeScript nếu không muốn bắt đầu từ đầu. Đặc điểm của cách dùng này là luôn có một bước build
mã thành JavaScript để sử dụng ở bước cuối cùng. Đối với Deno, chúng ta không cần phải vất vả như vậy nữa mặc định đã hỗ trợ TypeScript. Điều đó có nghĩa bạn có thể chạy một tệp .ts
trực tiếp với Deno.
# index.ts
const str: string = "Hello World!";
console.log(str);
Sau đó chỉ cần.
$ deno run index.ts
Hello World!
Thật tuyệt vời phải không nào.
npm là trình quản lý gói rất nổi tiếng đi kèm trong Node. Muốn cài thêm gói phụ thuộc nào chỉ cần dùng lệnh npm install
, các gói được tải đều nằm ở trên trang web npmjs.com. Khi tải về thì chúng nằm gọn trong thư mục node_modules
của dự án. Điều đó vô tình khiến node_modules
trở thành "hố đen vũ trụ" vì nó rất nặng. Chưa kể có bao nhiêu dự án Node, thì có bấy nhiêu thư mục node_modules
xuất hiện tạo nên tình trạng hoang phí tài nguyên bộ nhớ.
Deno không có node_modules
và package.json
. Deno không có một trình quản lý gói cụ thể nào, thay vào đó là cách import
hết sức độc đáo. Ví dụ như muốn dùng một gói nào từ một địa chỉ trên mạng ư? Rất đơn giản.
import { serve } from "https://deno.land/[email protected]/http/server.ts";
Hoặc với bất kỳ kho lưu trữ nào khác như jsr:
import { camelCase } from "jsr:@luca/cases";
Hay thậm chí là với npm:
import dayjs from "npm:dayjs"
Vậy thì npm install
lúc này tương ứng với câu lệnh nào trong Deno? Có khi bạn chẳng cần quan tâm lắm đâu vì chỉ cần với cú pháp import
như trên, mỗi khi chạy dự án bằng lệnh deno run
thì nó tự động tìm và tải xuống các gói cho bạn.
Mặc dù gần đây, Deno đang cố gắng hỗ trợ Node.js nên cách quản lý gói của Deno đang dần dần trở nên giống Node. Cho nên ở đây tôi nhấn mạnh rằng, nếu bạn chỉ đơn thuần sử dụng Deno, bạn thậm chí không cần quan tâm đến trình quản lý gói npm trong Node.
package.json
phải nó là một tệp cực kỳ quan trọng trong Node. Nó lưu giữ rất nhiều thông tin liên quan đến dự án như tên, phiên bản, các lệnh trong scripts
để khởi động và các gói phụ thuộc trong mục dependencies
.
Trong Deno chúng ta cũng có một tệp tương tự là deno.json
. Có cấu trúc gần giống như Node. Một điều kinh ngạc là bạn thậm chí không cần tệp cấu hình này trong Deno mà vẫn có thể chạy dự án một cách bình thường.
Node.js ra đời từ rất lâu về trước, thời điểm JavaScript còn chưa có hệ thống module chính thức. Khi đó Node chọn CommonJS làm hệ thống module mặc định. Sau này JavaScript công bố module gọi là ESM. Vì lẽ đó Node luôn tồn tại ít nhất 2 kiểu import là require
đại diện cho CommonJS và import/export
đại diện cho ESM. Chúng ta không thể sử dụng cùng lúc require
với import/export
, mặc dù vậy lại có nhiều công cụ hỗ trợ chuyển cú pháp require
thành import/export
hoặc ngược lại. Điều đó vô tình làm mã trở nên lộn xộn và nhiều khi không thể giải thích được bí ẩn đằng sau sự lai tạp hệ thống module này.
Deno chống lại sự lộn xộn này. Tức là giờ đây bạn chỉ cần quan tâm đến import/export
là đủ. Các gói dành cho Deno đều sử dụng cú pháp ESM. Thậm chí có những kho lưu trữ như jsr chỉ cho phép tải lên modules hỗ trợ mỗi ESM nhằm chống lại sự phân mảnh của hệ thống modules.
Trong Node, chỉ cần dùng một lệnh đơn giản để khởi động hầu hết ứng dụng. Ví dụ:
$ node index.js
Hoặc có thêm biến môi trường cùng với tham số đầu vào:
$ NODE_ENV=production node index.js debug
Deno thì không đơn giản như vậy. Tất cả quyền đều bị hạn chế theo mặc định. Bạn cần cung cấp quyền khi chạy. Các quyền đó bao gồm quyền truy cập vào hệ thống quản lý tệp tin, quyền truy cập mạng... Nếu không cấp quyền, trong khi ứng dụng lại sử dụng quyền đó thì sẽ nhận được thông báo lỗi. Ví dụ, để cấp quyền truy cập mạng:
$ deno run --allow-net index.ts
Hoặc nếu muốn "quay trở về" giống Node, cấp tất cả các quyền thì chỉ cần:
$ deno run -A index.ts
JavaScript không có công cụ kiểm tra và định dạng mã chính thức nào, kéo theo Node.js cũng vậy. Mặc dù có nhiều công cụ của bên thứ 3 làm được điều này nhưng nhìn chung chúng bị phân mảnh trong các dự án khác nhau. Tuỳ theo sở thích, phong cách của mỗi nhà phát triển.
Deno được tích hợp sẵn công cụ phân tích, định dạng và kiểm tra lỗi cú pháp, không cần phải sử dụng bên thứ 3 nào nữa. Tạo sự thống nhất cho toàn dự án.
Trong Node, chúng ta đều nghe đến cái tên Cluster, Child Process hay Worker Threads thường được dùng để xử lý đa luồng. Trong khi Cluster tận dụng đa lõi của CPU để nhân bản tiến trình thì Child Process hay Worker Threads tạo ra các tiến trình con để tăng hiệu suất xử lý, ngăn chặn vòng lặp sự kiện. Deno không có những thứ như vậy.
Deno cố gắng tuân thủ theo Web APIs cho nên giải pháp thay thế cho xử lý đa luồng lúc này là dựa trên Service Worker API. Cách triển khai ư? Web làm như thế nào thì với Deno làm y hệt. Đó là lợi ích của việc quy tất cả về một mối, cũng là lý do Deno tuân thử Web APIs để giảm áp lực cho lập trình viên.
Cả Node và Deno đều có cách vào chế độ gỡ lỗi y hệt nhau, đó là thêm cờ --inspect
.
$ deno run --inspect index.ts
Mặc dù ngay từ đầu Deno tuyên bố không hỗ trợ Node cũng như npm vì phần lớn các gói trên này tương thích hoặc sử dụng API của Node. Mà Deno được làm lại từ đầu, không liên quan cho nên không hỗ trợ Node APIs.
Qua thời gian, nhóm Deno nhận thấy việc không hỗ trợ này là một thiếu sót khó có thể chấp nhận được. Người dùng không thể từ bỏ kho lưu trữ khổng lồ từ npm, khiến Deno phải nhanh chóng quay trở lại với việc hỗ trợ Node.js. Trong các bản cập nhật mới nhất, họ tuyên bố Deno có thể chạy được hầu hết các gói trên npm hay thậm chí là sử dụng API của Node trong Deno luôn cũng được.
Ví dụ, fs
là một module nổi tiếng của Node. Vậy nhưng bạn vẫn có thể sử dụng fs
với Deno.
import * as fs from "node:fs";
Trên đây là một số điều nổi bật để bạn hình dung ra bức tranh khi di chuyển từ Node.js sang Deno. Nhìn chung không có quá nhiều khác biệt do cả 2 đều dùng JavaScript hoặc TypeScript. Sự khác biệt lớn nhất ở đây có thể là hệ thống module và trình quản lý gói. Làm quen được với 2 điểm này bạn sẽ sớm làm chủ được Deno.
Còn bạn thì sao? Đã sử dụng Deno trong dự án nào chưa? Có điều gì đáng lưu ý khi chuyển từ Node.js sang Deno mà chưa có trong bài viết không? Hãy để lại bình luận xuống phía dưới bài viết nhé. Xin cảm ơn!
Bí mật ngăn xếp của Blog
Là một lập trình viên, bạn có tò mò về bí mật công nghệ hay những khoản nợ kỹ thuật về trang blog này? Tất cả bí mật sẽ được bật mí ngay bài viết dưới đây. Còn chờ đợi gì nữa, hãy bấm vào ngay!
Đăng ký nhận thông báo bài viết mới
Bình luận (0)