Sử dụng plop để tự động tạo React component thông qua CLI

Nếu các bạn đã từng dùng thử ng generate - một công cụ siêu hữu ích trong Angular cho phép tạo các services, components từ command line, chắc hẳn các bạn cũng sẽ đặt câu hỏi liệu chúng ta có thể làm điều tương tự với React. Câu trả lời là hoàn toàn có thể, tuy nhiên, React không có chức năng này built-in, đòi hỏi chúng ta sẽ phải sử dụng tới một library có tên là plop

Plop là một library siêu nhẹ, cho phép người dùng generate code hoặc text file dựa trên các template có sẵn. Thay vì phải lặp đi lặp lại việc tạo file với cùng cấu trúc rồi import phần style tương ứng, bạn chỉ cần chạy một câu lệnh trong command line và.🌟BOOM. Mọi thứ đã được setup sẵn.

Trong bài viết này, mình sẽ hướng dẫn các bạn tạo một component đơn giản với plop. Các bạn có thể tìm hiểu thêm về những APIs khác trong document để có thể thoải mái tuỳ biến và generate ra bất cứ thứ gì mà bạn muốn: html, css, js, scss, ts,... 😆

Cấu trúc folder

Để các bạn dễ hình dung, mình sẽ giới thiệu sơ qua về cấu trúc folder hiện tại (Do mình dùng TypeScript nên đuôi file sẽ là TSX)

  1. src/components: chứa global components sẽ được sử dụng lại xuyên suốt dự án
  2. src/pages: chứa file TSX của component chỉ sử dụng một lần
  3. styles/pages: chứa style tương ứng của phần TSX ở trên

Mình sẽ thiết kế một generator, khi sử dụng sẽ tạo ra file TSX và SCSS tương ứng ở mục 2 và 3.

Sử dụng

Cài đặt

# Tải plop
npm install --save-dev plop

# Tạo một folder để chứa các template
mkdir plop-templates

# Tạo file plopfile.js ở root folder để cấu hình plop
touch plopfile.js

Tạo template

Trước khi chúng ta có thể generate ra một component, chúng ta cần phải khai báo cho plop biết rằng cấu trúc và hình hài của file đó sẽ trông như thế nào. Để làm điều này, các bạn tạo file Component.js.hbs trong folder plop-templates mà chúng ta đã tạo ở trên, và paste lại toàn bộ nội dung sau:

import React from 'react';

const {{pascalCase name}} = props => {
    return (
        <div>
            {{pascalCase name}}
        </div>
    );
};

export default {{pascalCase name}};

Ở trên là cấu trúc của một file functional component cơ bản trong React, tuy nhiên chắc hẳn các bạn sẽ thắc mắc {{pascalCase name}} là gì.

  • name: là tên của component - đây là một tham số được truyền vào khi chúng ta chạy câu lệnh plop để tạo component đó

  • pascalCase: giúp chúng ta format "name" thành dạng ViếtHoaMỗiChữCáiĐầuTiên

Cấu hình plop

Trong file plopfile.js mà chúng ta tạo ở trên, các bạn copy phần code sau:

module.exports = plop => {
	plop.setGenerator('component', {
		description: 'Tạo một component mới',
		prompts: [
			{
				type: 'input',
				name: 'name',
				message: 'Tên của component:',
			},
			{
				type: 'input',
				name: 'route',
				message: 'Đường dẫn tới component này:',
			},
		],
		actions: [
			{
				type: 'add',
				path: 'src/pages/{{pascalCase route}}/{{pascalCase name}}.tsx',
				templateFile: 'plop-templates/Component.tsx.hbs',
			},
			{
				type: 'add',
				path: 'src/styles/pages/{{pascalCase route}}/{{pascalCase name}}.scss',
			},
		],
	})
}
  1. Đầu tiên chúng ta sử dụng method setGenerator(name, config) để tạo ra một generator mới với plop.
  2. Trong phần prompts chúng ta sẽ cho phép người dùng nhập vào tên và đường dẫn của component mới. Nội dung người dùng nhập vào có thể được truy xuất thông qua tham số nameroute
  3. Thuộc tính actions sẽ là nơi cho phép chúng ta tạo file mới. Ở đây mình sẽ tạo file .tsx.scss với route và tên tương ứng như người dùng nhập vào. Sau đó, mình sử dụng thuộc tính templateFile để khai báo vị trí của template đã tạo ở trên. Đối với file .scss, do mình muốn để trống sau khi tạo nên sẽ không cần truyền vào thuộc tính templateFile

Tạo script trong package.json

"scripts": {
		"start": "node scripts/start.js",
		"build": "node scripts/build.js",
		"generate": "plop"
},

Kết quả

Okay, vậy là generator của chúng ta đã hoạt động, tuy nhiên nếu bạn để ý, file SCSS mới mà mình tạo chưa hề được tự động import vào index.scss. Chúng ta có thể làm điều này bằng cách thêm một "hành động" mới vào thuộc tính actions trong plopfile.js:

{
    type: 'append',
    path: 'src/styles/index.scss',
    pattern: `/* PLOP_COMPONENTS_IMPORT */`,
    template: `@import './pages{{pascalCase route}}/{{pascalCase name}}.scss';`,
}

Ở đây, thay vì tạo ra một file mới, generator sẽ thêm phần import vào file index.scss đã có sẵn. Plop sẽ tìm đường dẫn tới file này thông qua thuộc tính path, và dò xem dòng nào trong file này đang tồn tại chuỗi /* PLOP_COMPONENTS_IMPORT */ - điều này giúp bạn đảm bảo thứ tự import các file như ý muốn. Generator sẽ tự động thêm phần import trong thuộc tính template vào dòng tiếp theo. Vậy là chúng ta đã có thể tự động import và link các module với nhau sau khi tạo một component mới với plop generator.

Trên đây chỉ là một usecase cơ bản của plop. Mình hi vọng thông qua bài viết, các bạn có thể tận dụng library này để tạo ra những generator hữu ích giúp bạn và đồng đội làm việc hiệu quả hơn trong các dự án.


All Rights Reserved