Remember mpa multi-page application processing once

Keywords: Javascript npm supervisor JSON PHP

cause

Because domestic search engines are not friendly to single-page applications, the website of general websites is multi-page applications.

Choice

Being a website is certainly the best language in the world, PHP, which I wanted to do at first, but when I wrote this article, I was a front-end developer.
Considering maintainability, other front-ends may not be able to understand PHP code, so they choose node js.
Noejs is a well-known express ion that I think is appropriate, but the final deployment of the production environment is a virtual host, which does not support the node environment.--||
So we can only find a way to generate multiple static html files, that is, static website
Based on the above considerations, we finally choose express to develop and generate static pages.

Get ready

1. Create a new project folder mpa, run npm init, fill in the blanks, and then return all the way to get package.json

2. Install express, npm i express --save

3. Install ejs, npm i ejs --save
ejs is a template engine, because express's default template engine is jade,jade and html syntax are quite different.
So we need to install ejs,ejs can be considered as html + js mix

4. Install supervisor, npm i supervisor --save-dev
supervisor of nodejs is a hot deployment tool. Running express project directly only listens to the modification of template files, while the modification of js files needs to stop.
Restart will take effect. Start it with supervisor and it will monitor all file changes. Once there are file changes, restart immediately to achieve hot deployment.

configure directory

The project needs to include routing, internationalization, templates, static files, layout files, so the directory settings are as follows:

|-langs     //International Folder
    |-zh_CN.js
    |-en_US.js
|-layouts   //Layout Template Folder
    |-header.html
    |-footer.html
|-public    //Static Resource Folder
    |-static
        |-css
        |-js
        |-img
        |-vendor
|-views     //Content Template Folder
    |-*.html
|-index.js  //Main startup program
|-build.js  //Packed into Static File Programs
|-tools.js  //Custom Function Tool File

Main startup program

Write code in index.js

const express = require('express')
const fs = require('fs')
const path = require('path')
const app = express()
var ejs = require('ejs');
const tools = require('./tools')

app.engine('html', ejs.__express);  //  Configuration Template Engine
app.set('view engine', 'html')
app.use(express.static(path.join(__dirname, 'public')));

// To configure
var CONFIG = {
    port: 100,
    lang: 'zh_CN'
}
var langs =  require('./langs/'+CONFIG.lang);

// middleware
var setLang = (req, res, next) => {  //Loading corresponding internationalization files according to get parameters
  if (req.query.lang) {
      CONFIG.lang = req.query.lang
      langs =  require('./langs/'+CONFIG.lang);
  } else {
      langs =  require('./langs/zh_CN');
  }
  console.log(req.url +' '+ (new Date()))
  next()
}
app.use(setLang)

fs.readdirSync(path.join(__dirname, 'views')).map(file=>{  //Traverse the template file under the views folder and generate the corresponding routing according to the name of the template file
    // Route
    let route = file.substring(0,file.lastIndexOf('.'))
    if (route==='index') {
        app.get('/', (req, res) => {                        //Processing / and index homepage routing, code is almost the same, this block can be optimized
          res.render(file, {...langs[route],header:langs['header'],footer:langs['footer'],url:tools.url(langs.lang)})   //Transfer necessary parameters
        })
    }
    app.get('/'+route, (req, res) => {
      res.render(file, {...langs[route],header:langs['header'],footer:langs['footer'],url:tools.url(langs.lang)})
    })
    console.log(file.substring(0,file.lastIndexOf('.')))
})


// Service startup
app.listen(CONFIG.port, () => console.log(`app listening on port ${CONFIG.port}!`))

packaged applications

The steps for packaging are as follows

1. Traversing through langs files, how many internationalized files generate several internationalized folders

2. Traversing views files, rendering templates according to internationalized files, output html files to corresponding internationalized folders

3.copy static files to packaged directories

var ejs = require('ejs');
var fs = require('fs');
var path = require('path');//Resolve folders that need to be traversed
const tools = require('./tools')

var distType = 1
if (global.process.env.npm_config_argv) {
    let npmConfig = JSON.parse(global.process.env.npm_config_argv)
    if (npmConfig['original'][2] && npmConfig['original'][2]==='t2') {
        distType = 2;
    }
}

function delDir(path){
    let files = [];
    if(fs.existsSync(path)){
        files = fs.readdirSync(path);
        files.forEach((file, index) => {
            let curPath = path + "/" + file;
            if(fs.statSync(curPath).isDirectory()){
                delDir(curPath); //Remove folders recursively
            } else {
                fs.unlinkSync(curPath); //Delete files
            }
        });
        fs.rmdirSync(path);
    }
}

var viewPath = path.join( __dirname , 'views');
var outputPath = path.join(__dirname,'dist');

delDir(outputPath);
//process.exit();

if (!fs.existsSync(outputPath)) {
    fs.mkdirSync(outputPath)
}

const view = (filename)=>{
    return path.join(viewPath,filename + '.html');
}

var langFiles = fs.readdirSync(path.join(__dirname,'langs'));

if (distType===1) {
    langFiles.forEach((file)=>{
        var langPath = path.join(outputPath,file.substring(0,file.lastIndexOf('.')))
        if (!fs.existsSync(langPath)) {
            fs.mkdirSync(langPath)
        }
    }) 
    fs.readdir(viewPath,(err,files)=>{
        files.forEach((file) => {
            let stats = fs.statSync(path.join(viewPath,file));
            if (stats.isFile()) {
                langFiles.forEach((langFile)=>{
                    var local = langFile.substring(0,langFile.lastIndexOf('.'))
                    var langs =  require('./langs/'+local);
                    let name = file.substring(0,file.lastIndexOf('.'))
                    ejs.renderFile(view(name),{...langs[name],header:langs['header'],footer:langs['footer'],url:tools.url(langs.lang)},(err,str)=>{
                        fs.writeFile(path.join(outputPath,local,file), str, (err)=>{
                            if (err) {
                                console.log(`Establish ${path.join(outputPath,local,file)}fail`)
                            } else {
                                console.log(`Establish ${path.join(outputPath,local,file)}Success`)
                            }
                        })
                    });
                })
            }
        })
    })
} else if (distType===2) {
    fs.readdir(viewPath,(err,files)=>{
        files.forEach((file) => {
            let stats = fs.statSync(path.join(viewPath,file));
            if (stats.isFile()) {
                langFiles.forEach((langFile)=>{
                    var local = langFile.substring(0,langFile.lastIndexOf('.'))
                    var langs =  require('./langs/'+local);
                    let name = file.substring(0,file.lastIndexOf('.'))
                    let tplPtah = path.join(outputPath,name)
                    if (!fs.existsSync(tplPtah)) {
                        fs.mkdirSync(tplPtah)
                    }
                    let tplLangPath = path.join(tplPtah,local)
                    if (!fs.existsSync(tplLangPath)) {
                        fs.mkdirSync(tplLangPath)
                    }
                    let tplLangPathFile = path.join(tplLangPath,'index.html')
                    ejs.renderFile(view(name),{...langs[name],header:langs['header'],footer:langs['footer'],url:tools.url(langs.lang)},(err,str)=>{
                        fs.writeFile(tplLangPathFile, str, (err)=>{
                            if (err) {
                                console.log(`Establish ${tplLangPathFile}fail`)
                            } else {
                                console.log(`Establish ${tplLangPathFile}Success`)
                            }
                        })
                    });
                })
            }
        })
    })
}

const movePath = (fromPath,toPath)=>{
    if (!fs.existsSync(toPath)) {
        fs.mkdirSync(toPath)
    }
    fs.readdir(fromPath,(err,files)=>{
        files.forEach((file)=>{
            let filePath = path.join(fromPath,file)
            if (fs.statSync(filePath).isDirectory()) {
                movePath(path.join(fromPath,file),path.join(toPath,file));
            } else {
                fs.readFile(filePath,(err,str)=>{
                    if (err) {
                        console.log(`Copy ${filePath}fail`)
                    } else {
                        fs.writeFile(path.join(toPath,file),str, (err)=>{
                            if (err) {
                                console.log(`Establish ${path.join(toPath,file)}fail`)
                            } else {
                                console.log(`Establish ${path.join(toPath,file)}Success`)
                            }
                        })
                    }
                })
            }
        })
    })
}

movePath(path.join(__dirname,'public','static'),path.join(outputPath,'static'))

Configuration commands

Main configuration package.json file start command and package command

"scripts": {
    "start": "supervisor index.js",
    "build": "node build.js"
}

Scaffolding is finished and can be developed happily.^^

Posted by Mikkki on Thu, 25 Jul 2019 02:21:29 -0700