摘要:起因由于國內(nèi)的搜索引擎對單頁面應(yīng)用支持不友好,所以一般網(wǎng)站的網(wǎng)站做的是多頁面應(yīng)用選擇做網(wǎng)站當然是世界最好的語言啦,開始也是想這樣做的,但是在寫這篇文章的時候,自己是一枚前端開發(fā),考慮到可維護性,其他的前端未必能看懂代碼,所以還是在方面選型,
起因
由于國內(nèi)的搜索引擎對單頁面應(yīng)用支持不友好,所以一般網(wǎng)站的網(wǎng)站做的是多頁面應(yīng)用
選擇做網(wǎng)站當然是世界最好的語言PHP啦,開始也是想這樣做的,但是在寫這篇文章的時候,自己是一枚前端開發(fā),
考慮到可維護性,其他的前端未必能看懂PHP代碼,所以還是在nodejs方面選型,
nodejs有名的express我覺得挺合適,但是最終部署的生產(chǎn)環(huán)境是虛擬主機,不支持node環(huán)境,-_-||
所以只能想辦法生成多個靜態(tài)html文件,也就是網(wǎng)站靜態(tài)化
基于以上種種考慮,最終選擇用express開發(fā),最終生成靜態(tài)頁面
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項目只會監(jiān)聽模板文件的修改,而js文件的修改需要停止
再啟動才能生效,使用supervisor啟動它會監(jiān)聽所有文件的修改,一旦有文件修改,立馬重啟,從而實現(xiàn)熱部署
項目需要包含路由,國際化,模板,靜態(tài)文件,布局文件,所以目錄設(shè)置如下:
|-langs //國際化文件夾 |-zh_CN.js |-en_US.js |-layouts //布局模板文件夾 |-header.html |-footer.html |-public //靜態(tài)資源文件夾 |-static |-css |-js |-img |-vendor |-views //內(nèi)容模板文件夾 |-*.html |-index.js //主啟動程序 |-build.js //打包成靜態(tài)文件程序 |-tools.js //自定義函數(shù)工具文件主啟動程序
在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) => { //根據(jù)get參數(shù)加載對應(yīng)國際化文件 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文件夾下模板文件,根據(jù)模板文件名稱生成對應(yīng)路由 // 路由 let route = file.substring(0,file.lastIndexOf(".")) if (route==="index") { app.get("/", (req, res) => { //處理/ 和 index首頁路由,代碼幾乎一樣,這塊可以優(yōu)化 res.render(file, {...langs[route],header:langs["header"],footer:langs["footer"],url:tools.url(langs.lang)}) //傳遞必要參數(shù) }) } 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("."))) }) // 服務(wù)啟動 app.listen(CONFIG.port, () => console.log(`app listening on port ${CONFIG.port}!`))打包程序
打包的步驟如下
1.遍歷langs文件,有多少個國際化文件就生成幾個國際化文件夾
2.遍歷views文件,根據(jù)國際化文件渲染模板,輸出html文件到對應(yīng)國際化文件夾
3.copy靜態(tài)文件到打包目錄
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(`創(chuàng)建${path.join(outputPath,local,file)}失敗`) } else { console.log(`創(chuàng)建${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(`創(chuàng)建${tplLangPathFile}失敗`) } else { console.log(`創(chuàng)建${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(`創(chuàng)建${path.join(toPath,file)}失敗`) } else { console.log(`創(chuàng)建${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" }
腳手架完畢,可以愉快的開發(fā)了^_^
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/106034.html
摘要:而從技術(shù)實現(xiàn)角度,微前端架構(gòu)解決方案大概分為兩類場景單實例即同一時刻,只有一個子應(yīng)用被展示,子應(yīng)用具備一個完整的應(yīng)用生命周期。為了解決產(chǎn)品研發(fā)之間各種耦合的問題,大部分企業(yè)也都會有自己的解決方案。 原文鏈接:https://zhuanlan.zhihu.com/p/... Techniques, strategies and recipes for building a modern ...
摘要:原型首先確定項目需要的實現(xiàn)目標。第一部分第二部分第三部分第四部分 原型 首先 確定項目需要的實現(xiàn)目標。 第一部分 showImg(https://segmentfault.com/img/bVbrvMr?w=1304&h=888); 第二部分 showImg(https://segmentfault.com/img/bVbrvMN?w=1376&h=916); 第三部分 show...
摘要:其實就是我們開始掛載上去的我們在這里出去,我們就可以在回調(diào)里面只處理我們的業(yè)務(wù)邏輯,而其他如斷網(wǎng)超時服務(wù)器出錯等均通過攔截器進行統(tǒng)一處理。 showImg(https://segmentfault.com/img/remote/1460000015472616?w=845&h=622); 開始之前 隨著業(yè)務(wù)的不斷累積,目前我們 ToC 端主要項目,除去 node_modules, bu...
摘要:其實就是我們開始掛載上去的我們在這里出去,我們就可以在回調(diào)里面只處理我們的業(yè)務(wù)邏輯,而其他如斷網(wǎng)超時服務(wù)器出錯等均通過攔截器進行統(tǒng)一處理。 showImg(https://segmentfault.com/img/remote/1460000015472616?w=845&h=622); 開始之前 隨著業(yè)務(wù)的不斷累積,目前我們 ToC 端主要項目,除去 node_modules, bu...
使用webpack配置MPA 為什么需要使用 webpack 構(gòu)建多頁應(yīng)用呢?因為某些項目使用 SPA 不太合適(大多是 SEO 的原因),或者您在做項目時有其他的需求。如果你有如下需求: 使用 ES6 進行開發(fā) 期望使用面向?qū)ο箝_發(fā)(class) 自動壓縮合并 CSS 和 JS 文件 使用 ESLint 進行代碼檢查 自動生成 HTML 文件 自動抽取 CSS 文件 ... 有了這些需求,...
閱讀 3706·2021-11-11 16:55
閱讀 1651·2021-10-08 10:04
閱讀 3587·2021-09-27 13:36
閱讀 2770·2019-08-30 15:53
閱讀 1862·2019-08-30 11:17
閱讀 1265·2019-08-29 16:55
閱讀 2103·2019-08-29 13:57
閱讀 2523·2019-08-29 13:13