Trong bài viết này, chúng ta sẽ cùng nhau tạo một chương trình Node.js đơn giản, tạo một gói NPM và xuất bản nó trên npmjs.org.

Giả sử các bạn đã biết cơ bản về NodeJS, ít nhất là ở mức độ viết được chương trình Hello World.

Nếu bạn mới tìm hiểu Node.js, hãy tham gia khóa học miễn phí tại địa chỉ: https://vndemy.com/course/lap-trinh-node-js-co-ban-1/

OK. Bắt tay nào !

Chúng ta tạo một chương trình đơn giản Node.js như sau: Chương trình sẽ đọc một file với tên là “readme.txt” và biến đổi nội dung của nó thành chữ in hoa.

Rồi, hãy tạo thư mục tên là test và 1 file chương trình với tên là uppercaseme.js

// uppercaseme.js
"use strict"
var fs = require('fs');
var myfile = "readme.txt";

if(fs.existsSync(myfile)) {
    var content = fs.readFileSync(myfile, 'utf8');
    fs.writeFileSync(myfile, content.toUpperCase());
    console.log("Done");
} else {
    console.log("File does not exist - " + myfile);
}

Chương trình trên sẽ tìm 1 file tên là readme.txt và chuyển nội dung của nó thành in hoa và lưu lại. Sử dụng lệnh sau để chạy chương trình

node uppercaseme.js

Truyền vào tham số

Chương trình trên sử dụng hardcode, nên có vẻ không được ngon cho lắm. Giờ ta hãy sửa chương trình 1 chút để nhận thông tin tên của file như là 1 tham số của chương trình. Ta sẽ sử dụng tham số của ứng dụng bằng biến global process.argv theo cấu trúc của nó như sau:

node
<name-of-your-js-file>
....<additional arguments passed>

Và nội dung chương trình được sửa đổi như sau:

"use strict"
var fs = require('fs');
if(process.argv.length > 2) {
    // Read the first additional argument passed to the program
    var myfile = process.argv[2]; 

    if(fs.existsSync(myfile)) {
        var content = fs.readFileSync(myfile, 'utf8');
        fs.writeFileSync(myfile, content.toUpperCase());
        console.log("Done");
    } else {
        console.log("File does not exist - " + myfile);
    }
} else {
    console.log("ERROR: Pass on a file name/path");
}

Như trên thì chương trình sẽ nhận được 1 tham số là tên file ta truyền vào bằng dòng lệnh, nếu tên file không được truyền vào thì in ra 1 dòng thông báo lỗi

Để chạy chương trình ta dùng lệnh:

node uppercaseme readme.txt

Tạo mô đun Node

OK. Bài toán của ta đặt ra như thế này. Chúng cần tạo ra một chương trình để chuyển đổi nội dung của file hiện tại thành in hoa và thay thế file cũ. Và ta muốn chia sẻ chương trình này lên “in-toi-loét” cho cộng đồng sử dụng.

Và các developers khác có thể dùng lệnh sau để cài đặt và sử dụng mô đun Node mà ta đã chia sẻ công khai ở trên:

  • Cài đặt qua NPM
    npm install uppercase
  • Sử dụng lệnh/shell trên cmd/terminal
    uppercaseme <filename>
  • Sử dụng trong chương trình Node.js
    require('uppercaseme');

Để làm những việc trên, ta sẽ tạo một package với cấu trúc thư mục như sau:

test
    src
      -- bin
        -- uppercaseme 
      -- lib
        -- uppercaseme.js
      -- package.json
      -- README.md

    readme.txt

Sắp xếp lại dự án một chút bằng cách chuyển file uppercaseme.js vào trong thư mục lib. File readme.txt thì ta để nguyên đó.

Các file khác, tạm thời để rỗng, ta sẽ xử lý chúng ở phía sau. Trong thư mục dự án src được sử dụng để chương trình NPM quản lý.

  • package.json : Chứa thông tin cấu hình gói thư viện. File này bắt buộc phải có
  • README.md : File này chứa thông tin mô tả gói npm (tùy chọn có hoặc không) ta nên thêm vào, không thì NPM nó sẽ warning. Phong cách viết sử dụng định dạng Markdown

Giờ hãy kiểm tra lại chương trình để đảm bảo nó vẫn hoạt động tốt! (Giả sử ta vẫn ở trong thư mục test)

node ./src/lib/uppercaseme ./readme.txt

Nếu lỗi, hãy kiểm tra lại những thiếu xót hoặc đường dẫn sai.

OK. Giờ hãy sửa nội dung file src/bin/uppercaseme như sau. Chú ý là ta KHÔNG cần mở rộng .js cuối file này.

#!/usr/bin/env node

"use strict";
var path = require('path');
var fs = require('fs');
var lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib');

require(lib+'/uppercaseme.js').convert();

File trên sẽ cho phép sử dụng chương trình trên giao diện dòng lệnh. Ta sẽ phải cấu hình nó trong file package.json sau.

Hãy thử chạy chương trình trên xem có lỗi ko ?

node ./src/bin/uppercaseme ./readme.txt

Chắc chắn bạn sẽ thấy 1 lỗi như sau @@

require(lib+'/uppercaseme.js').convert();
                               ^
TypeError: Object #<Object> has no method 'convert'
    at Object.<anonymous> (...\src\bin\uppercaseme:8:32)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:901:3

Lỗi này là do trong file chương trình uppercaseme.js ta chưa định nghĩa hàm convert(). Hãy sửa lại chương trình như sau:

"use strict"
var fs = require('fs');

function convertThis() {
    if(process.argv.length > 2) {
        var myfile = process.argv[2];

        if(fs.existsSync(myfile)) {
            var content = fs.readFileSync(myfile, 'utf8');
            fs.writeFileSync(myfile, content.toUpperCase());
            console.log("Done");
        } else {
            console.log("File does not exist - " + myfile);
        }
    } else {
        console.log("Pass on a file name/path");
    }
}

exports.convert = convertThis;

Ngon rồi, hãy run kiểm tra lại chương trình 1 lần nữa:

node ./src/bin/uppercaseme ./readme.txt

Trên đây là chúng ta đã hoàn tất một mô đun đơn giản và sẵn sàng công khai, đưa gói lên thư viện NPM để chia sẻ với cộng đồng.

Tạo gói NPM

Đứng từ thư mục src ta sẽ cấu hình file package.json và Viết mô tả trong README.md

package.json được cấu hình theo định dạng JSON như sau:

{
  "author": "Anup Shinde",
  "name": "uppercaseme",
  "description": "Converts files to uppercase",
  "version": "0.1.1",
  "repository": {
    "url": ""
  },
  "main": "./lib/uppercaseme",
  "keywords": [
    "upper",
    "case",
    "file"
  ],
  "bin": {
    "uppercaseme": "./bin/uppercaseme"
  },
  "dependencies": {},
  "engines": {
    "node": "*"
  }
}

Ta có một vài chú thích cho thông tin cấu hình trên như sau:

main là ID của mô đun, tham chiếu đến chương trình chính.

name Trong ví dụ của ta, thì gói có tên là uppercaseme.

bin Khai báo cho phép ta thực thi chương trình qua giao diện dòng lệnh CMD/Terminal. NPM sẽ tự động cài đặt và link chương trình của ta vào PATH

dependencies Đây là danh sách gói thư viện mà chương trình của ta phụ thuộc. Hiện tại thì ta ko sử dụng thằng nào cả 😀

Chi tiết thêm về các tham số cấu hình trong package.json các bạn tham khảo thêm NPM-JS documentation


Giờ hãy viết một vài mô tả cho gói thư viện của ta trên NPM bằng cách sửa nội dung file README.md, ví dụ như dưới đây:

upper-case-me
-------------

This is a cool program to upper-case files

OK. Vậy là chúng ta đã hoàn tất xong công đoạn viết mã chương trình, tổ chức thư mục và giờ hãy publish nó lên NPMJS.ORG

Trước khi ta có thể publish được gói chương trình lên NPM registry, bạn cần phải đăng nhập NPM bằng lệnh adduser hoặc login

npm login

Hãy nhập thông tin username/email/password. Để hoàn tất đăng nhập

Hãy di chuyển vào thư mục src và thực hiện lệnh publish để tải lên:

npm publish

Có thể bạn sẽ nhìn thấy đoạn log như sau:

npm http PUT https://registry.npmjs.org/uppercaseme
npm http 201 https://registry.npmjs.org/uppercaseme
npm http GET https://registry.npmjs.org/uppercaseme
npm http 200 https://registry.npmjs.org/uppercaseme
npm http PUT https://registry.npmjs.org/uppercaseme/-/uppercaseme-0.1.1.tgz/-rev/1-74d3bb0b59747a421
5b7b3778dcc02c0
npm http 201 https://registry.npmjs.org/uppercaseme/-/uppercaseme-0.1.1.tgz/-rev/1-74d3bb0b59747a421
5b7b3778dcc02c0
npm http PUT https://registry.npmjs.org/uppercaseme/0.1.1/-tag/latest
npm http 201 https://registry.npmjs.org/uppercaseme/0.1.1/-tag/latest
+ uppercaseme@0.1.1

Quá trình upload thành công !!!!

Cài đặt gói NPM của ta

Giờ hãy quay ra ngoài 1 bậc so với thư mục test. Tạo 1 thư mục, đặt tên là testpack và di chuyển vào testpack, gõ lệnh sau để cài đặt:

npm install uppercaseme

NPM tự động cài đặt gói uppercaseme của ta trên NPM repo và cài đặt vào local trong thư mục ./node_modules. Hãy kiểm tra nó bằng cách tạo 1 file với tên testMyFile.txt trong thư mục testpack và nhập 1 vài nội dung trong nó (chú ý đặt 1 vài ký tự in thường nhé) và gõ lệnh:

./node_modules/.bin/uppercaseme testMyFile.txt

Kiểm tra kết quả của chương trình !


Ta có thể cài đặt global cho chương trình này bằng việc thêm 1 tham số -g vào lệnh cài đặt để NPM sẽ cài vào thư mục global do NPM quản lý. Khi đó ta không nhìn thấy thư mục ./node_modules trong thư mục testpack nữa.

npm install -g uppercaseme

Và cách sử dụng của ta chỉ cần gõ lệnh uppercaseme là được:

uppercaseme testMyFile.txt

Sử dụng gói thư viện trong chương trình

Như các gói thư viện khác, ta có thể sử dụng lại chương trình của ta bằng lệnh require trong chương trình.

Vẫn ở trong thư mục testpack tạo 1 file mới là test.js như sau:

var ucm = require("uppercaseme");
ucm.convert();

Hoặc có thể viết lại đoạn mã trên ngắn gọn hơn như sau:

require("uppercaseme").convert();

Và chạy chương trình:

node test.js testMyFile.txt

Một số lỗi có thể xảy ra

1) Nếu có lỗi Error: Cannot find module '...', là do khi ta cài đặt global NodeJS không thể tìm thấy gói mới cài đặt.

Hãy kiểm tra biến môi trường NODE_PATH

Linux:
echo $NODE_PATH

Windows:
echo %NODE_PATH%

Nếu lệnh trên không hiển thị giá trị nào, hãy sửa lại bằng lệnh:

Linux:
export NODE_PATH=/usr/local/lib/node_modules

Windows:
set NODE_PATH=%USERPROFILE%\AppData\Roaming\npm\node_modules

2) Chạy chương trình trên Windows thì ok, nhưng trên Linux thì lỗi, với thông báo :No such file or directory

Lỗi này do ta phát triển gói mô đun trên Windows chứa ký tự '\r' Do đó khi cài đặt qua npm install trên Linux thì nó không hiểu ký tự '\r'

Các bạn tự tìm cách sửa nhé 😀

Chúc ae vọc thành công nhé !

Bài viết này viết lại của tác giả Anup Shinde: Tham khảo bài viết gốc

http://www.anupshinde.com/posts/how-to-create-nodejs-npm-package/

About The Author

  • duong thua Tuong

    Chào anh, cám ơn anh bài viết rất hay. Anh ơi cho em hỏi em đã cài biến môi trường NODE_PATH=%USERPROFILE%AppDataRoamingnpmnode_modules nhưng khi em cài thêm module mới nó vẫn thông báo npm should be run outside of the node repl, in your normal shell, giờ làm thế nào ạ, em cám ơn