资讯专栏INFORMATION COLUMN

记一次mpa多页面应用处理

lei___ / 1255人阅读

摘要:起因由于国内的搜索引擎对单页面应用支持不友好,所以一般网站的网站做的是多页面应用选择做网站当然是世界最好的语言啦,开始也是想这样做的,但是在写这篇文章的时候,自己是一枚前端开发,考虑到可维护性,其他的前端未必能看懂代码,所以还是在方面选型,

起因

由于国内的搜索引擎对单页面应用支持不友好,所以一般网站的网站做的是多页面应用

选择

做网站当然是世界最好的语言PHP啦,开始也是想这样做的,但是在写这篇文章的时候,自己是一枚前端开发,
考虑到可维护性,其他的前端未必能看懂PHP代码,所以还是在nodejs方面选型,
nodejs有名的express我觉得挺合适,但是最终部署的生产环境是虚拟主机,不支持node环境,-_-||
所以只能想办法生成多个静态html文件,也就是网站静态化
基于以上种种考虑,最终选择用express开发,最终生成静态页面

准备

1.新建项目文件夹mpa,运行npm init,该填的填写,然后一路回车,得到package.json

2.安装express,npm i express --save

3.安装ejs,npm i ejs --save
ejs是一个模板引擎,因为express默认的模板引擎是jade,jade与html语法相差较大,
所以我们要安装ejs,ejs可以认为就是html语言+js混编

4.安装supervisor,npm i supervisor --save-dev
nodejs的supervisor是一个热部署工具,直接运行express项目只会监听模板文件的修改,而js文件的修改需要停止
再启动才能生效,使用supervisor启动它会监听所有文件的修改,一旦有文件修改,立马重启,从而实现热部署

配置目录

项目需要包含路由,国际化,模板,静态文件,布局文件,所以目录设置如下:

|-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编写代码

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"
}

脚手架完毕,可以愉快的开发了^_^

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106034.html

相关文章

  • 可能是你见过最完善的微前端解决方案

    摘要:而从技术实现角度,微前端架构解决方案大概分为两类场景单实例即同一时刻,只有一个子应用被展示,子应用具备一个完整的应用生命周期。为了解决产品研发之间各种耦合的问题,大部分企业也都会有自己的解决方案。 原文链接:https://zhuanlan.zhihu.com/p/... Techniques, strategies and recipes for building a modern ...

    Kahn 评论0 收藏0
  • 项目:(MPA应用)企业展示 页面布局以及样式开发

    摘要:原型首先确定项目需要的实现目标。第一部分第二部分第三部分第四部分 原型 首先 确定项目需要的实现目标。 第一部分 showImg(https://segmentfault.com/img/bVbrvMr?w=1304&h=888); 第二部分 showImg(https://segmentfault.com/img/bVbrvMN?w=1376&h=916); 第三部分 show...

    JerryC 评论0 收藏0
  • 浅谈使用 Vue 构建前端 10w+ 代码量的单页面应用开发底层

    摘要:其实就是我们开始挂载上去的我们在这里出去,我们就可以在回调里面只处理我们的业务逻辑,而其他如断网超时服务器出错等均通过拦截器进行统一处理。 showImg(https://segmentfault.com/img/remote/1460000015472616?w=845&h=622); 开始之前 随着业务的不断累积,目前我们 ToC 端主要项目,除去 node_modules, bu...

    rickchen 评论0 收藏0
  • 浅谈使用 Vue 构建前端 10w+ 代码量的单页面应用开发底层

    摘要:其实就是我们开始挂载上去的我们在这里出去,我们就可以在回调里面只处理我们的业务逻辑,而其他如断网超时服务器出错等均通过拦截器进行统一处理。 showImg(https://segmentfault.com/img/remote/1460000015472616?w=845&h=622); 开始之前 随着业务的不断累积,目前我们 ToC 端主要项目,除去 node_modules, bu...

    Backache 评论0 收藏0
  • ➹使用webpack配置页面应用(MPA)

    使用webpack配置MPA 为什么需要使用 webpack 构建多页应用呢?因为某些项目使用 SPA 不太合适(大多是 SEO 的原因),或者您在做项目时有其他的需求。如果你有如下需求: 使用 ES6 进行开发 期望使用面向对象开发(class) 自动压缩合并 CSS 和 JS 文件 使用 ESLint 进行代码检查 自动生成 HTML 文件 自动抽取 CSS 文件 ... 有了这些需求,...

    rainyang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<