記一次mpa多頁面應用處理

原由

因爲國內的搜索引擎對單頁面應用支持不友好,因此通常網站的網站作的是多頁面應用css

選擇

作網站固然是世界最好的語言PHP啦,開始也是想這樣作的,可是在寫這篇文章的時候,本身是一枚前端開發,
考慮到可維護性,其餘的前端未必能看懂PHP代碼,因此仍是在nodejs方面選型,
nodejs有名的express我以爲挺合適,可是最終部署的生產環境是虛擬主機,不支持node環境,-_-||
因此只能想辦法生成多個靜態html文件,也就是網站靜態化
基於以上種種考慮,最終選擇用express開發,最終生成靜態頁面html

準備

1.新建項目文件夾mpa,運行npm init,該填的填寫,而後一路回車,獲得package.json前端

2.安裝express,npm i express --savenode

3.安裝ejs,npm i ejs --save
ejs是一個模板引擎,由於express默認的模板引擎是jade,jade與html語法相差較大,
因此咱們要安裝ejs,ejs能夠認爲就是html語言+js混編express

4.安裝supervisor,npm i supervisor --save-dev
nodejs的supervisor是一個熱部署工具,直接運行express項目只會監聽模板文件的修改,而js文件的修改須要中止
再啓動才能生效,使用supervisor啓動它會監聽全部文件的修改,一旦有文件修改,立馬重啓,從而實現熱部署npm

配置目錄

項目須要包含路由,國際化,模板,靜態文件,佈局文件,因此目錄設置以下:json

|-langs     //國際化文件夾
    |-zh_CN.js
    |-en_US.js
|-layouts   //佈局模板文件夾
    |-header.html
    |-footer.html
|-public    //靜態資源文件夾
    |-static
        |-css
        |-js
        |-img
        |-vendor
|-views     //內容模板文件夾
    |-*.html
|-index.js  //主啓動程序
|-build.js  //打包成靜態文件程序
|-tools.js  //自定義函數工具文件

主啓動程序

在index.js編寫代碼app

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);  //  配置模板引擎
app.set('view engine', 'html')
app.use(express.static(path.join(__dirname, 'public')));

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

// 中間件
var setLang = (req, res, next) => {  //根據get參數加載對應國際化文件
  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=>{  //遍歷views文件夾下模板文件,根據模板文件名稱生成對應路由
    // 路由
    let route = file.substring(0,file.lastIndexOf('.'))
    if (route==='index') {
        app.get('/', (req, res) => {                        //處理/ 和 index首頁路由,代碼幾乎同樣,這塊能夠優化
          res.render(file, {...langs[route],header:langs['header'],footer:langs['footer'],url:tools.url(langs.lang)})   //傳遞必要參數
        })
    }
    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('.')))
})


// 服務啓動
app.listen(CONFIG.port, () => console.log(`app listening on port ${CONFIG.port}!`))

打包程序

打包的步驟以下函數

1.遍歷langs文件,有多少個國際化文件就生成幾個國際化文件夾工具

2.遍歷views文件,根據國際化文件渲染模板,輸出html文件到對應國際化文件夾

3.copy靜態文件到打包目錄

var ejs = require('ejs');
var fs = require('fs');
var path = require('path');//解析須要遍歷的文件夾
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); //遞歸刪除文件夾
            } else {
                fs.unlinkSync(curPath); //刪除文件
            }
        });
        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(`建立${path.join(outputPath,local,file)}失敗`)
                            } else {
                                console.log(`建立${path.join(outputPath,local,file)}成功`)
                            }
                        })
                    });
                })
            }
        })
    })
} 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(`建立${tplLangPathFile}失敗`)
                            } else {
                                console.log(`建立${tplLangPathFile}成功`)
                            }
                        })
                    });
                })
            }
        })
    })
}

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(`拷貝${filePath}失敗`)
                    } else {
                        fs.writeFile(path.join(toPath,file),str, (err)=>{
                            if (err) {
                                console.log(`建立${path.join(toPath,file)}失敗`)
                            } else {
                                console.log(`建立${path.join(toPath,file)}成功`)
                            }
                        })
                    }
                })
            }
        })
    })
}

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

配置命令

主要配置package.json文件的啓動命令和打包命令

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

腳手架完畢,能夠愉快的開發了^_^

相關文章
相關標籤/搜索