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.^^