jianghu-init Exploration

12002

1. Introduction to jianghu-init

  • What is jianghu-init and what problems does it solve?

jianghu-init is a command-line tool provided by the JianghuJS framework that allows developers to quickly generate a project framework that conforms to JianghuJS standards. It addresses the following main issues:

  1. Quick project initialization:
    With a simple command, developers can quickly initialize a JianghuJS project without manually creating project structures and configuration files.

  2. Standardized project structure:
    jianghu-init provides a standardized project structure, ensuring consistency across projects, which is beneficial for team collaboration and project maintenance.

  3. Default configuration options:
    It offers several default configuration options, reducing configuration complexity while retaining flexibility, allowing developers to customize configurations as needed.

  4. Integrated front-end and back-end configuration:
    The automatically generated project framework integrates Vuetify front-end page templates and back-end database configurations, enabling developers to quickly set up a complete application.

  5. Reduced learning curve:
    New developers can quickly obtain a standard development environment through jianghu-init, lowering the learning curve and improving project maintainability.

    The directory structure of a JianghuJS project is as follows:

├── config                                                # egg config
│   ├── config.default.js                            # default config                    
│   ├── config.local.js                               # config used during npm run dev
│   ├── config.prod.js                               # config used during npm run start
│   ├── config.unittest.js                           # config used during npm run test
│   └── plugin.js                                      # egg plugin configuration
├── app 
│   ├── common                                       # Common tools and static methods for the project    
│   ├── constant                                       # Constants   
│   │   ├── constant.js
│   │   └── error.js
│   ├── controller                                     # Exposed interfaces 
│   ├── public                                          # Static resource directory 
│   ├── schedule                                      # Scheduled tasks; refer to https://www.eggjs.org/en/basics/schedule
│   ├── service                                         # Application protocol service directory
│   └── view                                            # Directory for storing pages
├── app.js                                                # Custom initialization work at startup
├── jsconfig.json
├── package.json
├── sql                                                    # SQL files
│   └── init.sql
└── upload                          
  • Usage of jianghu-init

  • Basic Environment
    Operating System: Windows/macOS/Linux
    Runtime Environment: Node.js v16.x
    Database Environment: Mysql5.7+

  • Development Tools
    Development Tool: Vscode
    Database Development Tool: Navicat

  • Installing jianghu-init

# Uninstall/remove old version of jianghu-init
$ npm uninstall -g jianghu-init
$ npm uninstall -g @jianghujs/jianghu-init
# Install the latest version of jianghu-init
$ npm install -g @jianghujs/jianghu-init
# Check version
$ npm list @jianghujs/jianghu-init -g
  • Running jianghu-init

    • Open cmd, enter the jianghu-init command, and select the type of project you want to create.

    jhinit1.png

    • After selection, enter the name of the project you want to create and specify the path.

    jhinit2.png

    • Confirm the project name and data name.

    jhinit3.png

    • Confirm the database information and successfully create the project.

    jhinit4.png

    • Locate your newly created project my-project, open it with vscode, run the terminal, and install dependencies.

    jhinit5.png

    • Confirm in Navicat that the project's database already exists.

    jhinit6.png

    • After installing the dependencies, start the project and access it in the browser at http://127.0.0.1:7001.

    jhinit7.png

    • Enter username admin and password 123456.

    jhinit8.png

    • Login successful, you can now develop on this project!

    jhinit9.png

2. Case Study: JianghuJS - Server-Side Rendering

  • jianghujs-server-render

  • Introduction

    server-render mainly demonstrates how to mount data to the ctx context and render data using the template engine nunjucks. In a front-end and back-end separated project structure, requests are typically made to call APIs to obtain the required data, which is then rendered to the page. However, the server-render mode does not initiate a request to fetch data; instead, it renders the template on the server and returns the page to the front end. Server-side rendering can improve the initial page load speed and SEO optimization, and is generally used for websites that require SEO and content.

  • Project Overview

    The server-render project includes the following pages:

    • Article Management

    server-render-01.png

    • Server-Side Rendering

    server-render-01.png

This article mainly uses the jianghujs-server-render/app/view/page/home.html in the project directory as an example to explain the implementation of server-side rendering. For courses related to article management, please refer to the Template - Advanced - SEO course.

  • Implementation of Server-Side Rendering
  1. Bind the service method under the pageHook field in the _page table and define the variable names to be used in the template.
// Under the pageHook of home, we bind two service methods
{
  "beforeHook":[
    // When the page is rendered, the test method in njk service will be called
    {"service": "njk", "serviceFunc": "test"},
    // When the page is rendered, the getCategoryListAndArticleList method in article service will be called, and the data will be bound to the categoryList variable
    {"templateVar": "categoryList", "service": "article", "serviceFunc": "getCategoryListAndArticleList"}
  ]
}
  1. Implement the methods defined under the pageHook field in the _page table in the service.
// Implementing the test method in njk service
class NjkService extends Service {

  async test() {
    this.ctx.seo = this.ctx.seo || {}
    this.ctx.seo.article = {
      string: 'Server-Side Rendering Demo',
    };
  }
}

module.exports = NjkService;

// Implementing the getCategoryListAndArticleList method in article service
class ArticleService extends Service {

  async getCategoryListAndArticleList() {
    const {ctx, app} = this;
    const {jianghuKnex} = app;

    let categoryList = await jianghuKnex(tableEnum.view01_category).select('categoryId', 'categoryName');

    return categoryList;

  }
}

module.exports = ArticleService;
  1. Use the data returned from the service in home.html.
// Using the data defined in the ctx context in njk service
<div><$ ctx.seo.article.string $></div>

// Using the data returned from article service, which is bound to the categoryList variable
{% for item in categoryList %}
  <div><$ item.categoryName $></div>
{% endfor %}

3. Case Study: JianghuJS - Page Two-Factor Authentication

  • Purpose of Page Two-Factor Authentication

By setting a password (passcode) on the page, the security of the page is enhanced. When users access a page that has a password set, they need to enter the correct password to access the page normally; otherwise, access is denied. After entering the correct password, users do not need to enter the password again for a certain period, which can be adjusted by modifying the configuration on the page.

  • Configuring Two-Factor Authentication for the Page

  • Database Modification

  1. Structural Modification: Add a column passcode in the _page table of the database, with a data type of VARCHAR(255).
    ALTER TABLE `_page`  ADD COLUMN `passcode` varchar(255) NULL COMMENT 'Page two-factor authentication; passcode ' AFTER `sort`;
  1. Configure the password for the page: In the _page table, find the page to which you want to add a password, enter the password in the passcode field, and save it.

Note: If the passcode field is empty, it is equivalent to the page not having a password set.

  • Adding Components to the Page
  1. Add component file:
    Create /app/view/component/pagePasscodeValidation.html in the project folder.

  2. Include the component in the page:
    In the project folder /app/page/password.html, include the pagePasscodeValidation component.

    {% include 'component/pagePasscodeValidation.html' %}

    In the HTML part of the page, add the following component:

    <page-passcode-validation validation-duration-hour="1"></page-passcode-validation>

    Here, validation-duration-hour is the validity period of the current password authentication, calculated in hours. Modifying this value will adjust the validity period of the password authentication.

  3. Storage & Validation Logic

Setting validation time cache

let pageValidationObj = {}
try {
  const pageValidationObjStr = localStorage.getItem(`${window.appInfo.appId}_page_validation_obj`);
  pageValidationObj = JSON.parse(pageValidationObjStr || '{}');
} catch (error) {
  console.error("[cachePageValidation]", "json data exception");
}
pageValidationObj[pageId] = value;
localStorage.setItem(`${window.appInfo.appId}_page_validation_obj`, JSON.stringify(pageValidationObj));

Validating authentication information

if (this.passcodeOfUser !== this.passcodeOfServer) {
  window.vtoast.fail({message: 'Page authentication failed'});
}
if (this.passcodeOfUser === this.passcodeOfServer) {
  this.cachePageValidation({
    pageId: this.pageId,
    value: {
      pageId: this.pageId,
      date: dayjs(),
      success: true,
    }
  });
  this.isPageValidationDialogShown = false;
}