目錄
取得節點和節點庫
nodePress.js
本地运行
结论
首頁 web前端 js教程 建立內容管理系統:nodePress

建立內容管理系統:nodePress

Sep 03, 2023 pm 01:53 PM

<p>您已使用 Go 成功建立了平面檔案系統內容管理系統 (CMS)。下一步是採用同樣的理念,使用 Node.js 製作一個 Web 伺服器。我將向您展示如何載入庫、建立伺服器和運行伺服器。 </p> <p>此 CMS 將使用第一個教學課程「建立 CMS:結構和樣式」中介紹的網站資料結構。因此,請下載此基本結構並將其安裝在新目錄中。 </p> <h2 id="取得節點和節點庫">取得節點和節點庫</h2> <p>在 Mac 上安裝 Node.js 最簡單的方法是使用 Homebrew。如果您尚未安裝 Homebrew,教學 Homebrew 揭秘:OS X 的終極套件管理器將向您展示如何安裝。 </p> <p>要使用 Homebrew 安裝 Node.js,請在終端機中輸入以下指令:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>brew install node </pre><div class="contentsignin">登入後複製</div></div> <p>完成後,您的 Mac 上將完全安裝了 Node 和 npm 命令。對於所有其他平台,請按照 Node.js 網站上的說明進行操作。 </p> <p>請注意:許多套件管理器目前正在安裝 Node.js 版本 0.10。本教學假設您擁有 5.3 或更高版本。您可以鍵入以下內容來檢查您的版本:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>node --version </pre><div class="contentsignin">登入後複製</div></div> <p><code class="inline">node</code> 指令執行 JavaScript 解譯器。 <code class="inline">npm</code> 指令是 Node.js 的套件管理器,用於安裝新程式庫、建立新專案以及執行專案腳本。 Envato Tuts 上有許多關於 Node.js 和 NPM 的精彩教學和課程。 </p> <p>要安裝 Web 伺服器的庫,您必須在 Terminal.app 或 iTerm.app 程式中執行以下命令:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>npm install express --save npm install handlebars --save npm install moment --save npm install marked --save npm install jade --save npm install morgan --save </pre><div class="contentsignin">登入後複製</div></div> <p>Express 是一個 Web 應用程式開發平台。它類似Go中的goWeb函式庫。 Handlebars 是用於建立頁面的模板引擎。 Moment 是一個用於處理日期的函式庫。 Marked 是一個很棒的 JavaScript 中 Markdown 到 HTML 轉換器。 Jade 是一種 HTML 速記語言,可輕鬆建立 HTML。 Morgan 是 Express 的中間件庫,可產生 Apache 標準日誌檔案。 </p> <p>安裝庫的另一種方法是下載本教學的來源檔案。下載並解壓縮後,在主目錄中輸入:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>npm --install </pre><div class="contentsignin">登入後複製</div></div> <p>這將安裝創建該專案所需的一切。 </p> <h2 id="nodePress-js">nodePress.js</h2> <p>現在您可以開始建立伺服器了。在專案的頂層目錄中,建立一個名為 nodePress.js 的文件,在您選擇的編輯器中開啟它,然後開始新增以下程式碼。我將解釋放入文件中的程式碼。 </p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// // Load the libraries used. // var fs = require('fs'); var path = require("path"); var child_process = require('child_process'); var process = require('process'); var express = require('express'); // http://expressjs.com/en/ var morgan = require('morgan'); // https://github.com/expressjs/morgan var Handlebars = require("handlebars"); // http://handlebarsjs.com/ var moment = require("moment"); // http://momentjs.com/ var marked = require('marked'); // https://github.com/chjj/marked var jade = require('jade'); // http://jade-lang.com/ </pre><div class="contentsignin">登入後複製</div></div> <p>伺服器程式碼從初始化用於建立伺服器的所有程式庫開始。沒有帶有網址的註解的函式庫是內部 Node.js 函式庫。 </p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// // Setup Global Variables. // var parts = JSON.parse(fs.readFileSync('./server.json', 'utf8')); var styleDir = process.cwd() + '/themes/styling/' + parts['CurrentStyling']; var layoutDir = process.cwd() + '/themes/layouts/' + parts['CurrentLayout']; var siteCSS = null; var siteScripts = null; var mainPage = null; </pre><div class="contentsignin">登入後複製</div></div> <p>接下來,我設定所有全域變數和庫配置。使用全域變數並不是最好的軟體設計實踐,但它確實有效並有助於快速開發。 </p> <p><code class="inline">parts</code> 變數是一個包含網頁所有部分的雜湊數組。每個頁面都引用該變數的內容。它從伺服器目錄頂部的 server.json 檔案的內容開始。 </p> <p>然後,我使用 server.json 檔案中的資訊來建立用於此網站的 <code class="inline">styles</code> 和 <code class="inline">layouts</code> 目錄的完整路徑。 </p> <p>接著將三個變數設定為空值:<code class="inline">siteCSS</code>、<code class="inline">siteScripts</code> 和 <code class="inline">mainPage</code>。這些全域變數將包含所有 CSS、JavaScript 和主索引頁內容。這三個項目是任何 Web 伺服器上要求最多的項目。因此,將它們保留在記憶體中可以節省時間。如果 server.json 檔案中的 <code class="inline">Cache</code> 變數為 false,則每個請求都會重新讀取這些項目。 </p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>marked.setOptions({ renderer: new marked.Renderer(), gfm: true, tables: true, breaks: false, pedantic: false, sanitize: false, smartLists: true, smartypants: false }); </pre><div class="contentsignin">登入後複製</div></div> <p>此程式碼區塊用於配置 Marked 庫以從 Markdown 產生 HTML。大多數情況下,我會打開表格和 smartLists 支援。 </p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>parts["layout"] = fs.readFileSync(layoutDir + '/template.html', 'utf8'); parts["404"] = fs.readFileSync(styleDir + '/404.html', 'utf8'); parts["footer"] = fs.readFileSync(styleDir + '/footer.html', 'utf8'); parts["header"] = fs.readFileSync(styleDir + '/header.html', 'utf8'); parts["sidebar"] = fs.readFileSync(styleDir + '/sidebar.html', 'utf8'); // // Read in the page parts. // var partFiles = fs.readdirSync(parts['Sitebase'] + "parts/"); partFiles.forEach(function(ele, index, array) { parts[path.basename(ele, path.extname(ele))] = figurePage(parts['Sitebase'] + "parts/" + path.basename(ele, path.extname(ele))); }); </pre><div class="contentsignin">登入後複製</div></div> <p><code class="inline">parts</code> 變數進一步載入 <code class="inline">styles</code> 和 <code class="inline">layout</code> 目錄中的部分。 <code class="inline">site</code> 目錄內的 <code class="inline">parts</code> 目錄中的每個檔案也被載入到 <code class="inline">parts</code> 全域變數中。不含副檔名的檔案名稱是用來儲存檔案內容的名稱。這些名稱在 Handlebars 巨集中會擴展。 </p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// // Setup Handlebar's Helpers. // // // HandleBars Helper: save // // Description: This helper expects a // "<name>" "<value>" where the name // is saved with the value for future // expansions. It also returns the // value directly. // Handlebars.registerHelper("save", function(name, text) { // // Local Variables. // var newName = "", newText = ""; // // See if the name and text is in the first argument // with a |. If so, extract them properly. Otherwise, // use the name and text arguments as given. // if(name.indexOf("|") > 0) { var parts = name.split("|"); newName = parts[0]; newText = parts[1]; } else { newName = name; newText = text; } // // Register the new helper. // Handlebars.registerHelper(newName, function() { return newText; }); // // Return the text. // return newText; }); // // HandleBars Helper: date // // Description: This helper returns the date // based on the format given. // Handlebars.registerHelper("date", function(dFormat) { return moment().format(dFormat); }); // // HandleBars Helper: cdate // // Description: This helper returns the date given // in to a format based on the format // given. // Handlebars.registerHelper("cdate", function(cTime, dFormat) { return moment(cTime).format(dFormat); }); </pre><div class="contentsignin">登入後複製</div></div> <p>下一段程式碼定義了我定義的在 Web 伺服器中使用的 Handlebars 幫助程式:<code class="inline">save</code>、<code class="inline">date</code> 和 <code class="inline">cdate</code>。儲存助手允許在頁面內建立變數。此版本支援 goPress 版本,其中參數的名稱和值一起以「|」分隔。您也可以使用兩個參數指定保存。例如:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>{{save "name|Richard Guay"}} {{save "newName" "Richard Guay"}} Name is: {{name}} newName is: {{newName}} </pre><div class="contentsignin">登入後複製</div></div> <p>這將產生相同的結果。我更喜歡第二種方法,但 Go 中的 Handlebars 庫不允許使用多個參數。 </p> <p><code class="inline">date</code> 和 <code class="inline">cdate</code> 帮助程序格式化当前日期 (<code class="inline">date</code>) 或给定日期 (<code class="inline">cdate</code>)根据 <strong>moment.js</strong> 库格式化规则。 <code class="inline">cdate</code> 帮助程序期望渲染的日期是第一个参数并且具有 ISO 8601 格式。</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// // Create and configure the server. // var nodePress = express(); // // Configure middleware. // nodePress.use(morgan('combined')) </pre><div class="contentsignin">登入後複製</div></div> <p>现在,代码创建一个 Express 实例来配置实际的服务器引擎。 <code>nodePress.use()</code> 函数设置中间件软件。中间件是在每次调用服务器时提供服务的任何代码。在这里,我设置了 Morgan.js 库来创建正确的服务器日志输出。</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// // Define the routes. // nodePress.get('/', function(request, response) { setBasicHeader(response); if((parts["Cache"] == true) && (mainPage != null)) { response.send(mainPage); } else { mainPage = page("main"); response.send(mainPage); } }); nodePress.get('/favicon.ico', function(request, response) { var options = { root: parts['Sitebase'] + 'images/', dotfiles: 'deny', headers: { 'x-timestamp': Date.now(), 'x-sent': true } }; response.set("Content-Type", "image/ico"); setBasicHeader(response); response.sendFile('favicon.ico', options, function(err) { if (err) { console.log(err); response.status(err.status).end(); } else { console.log('Favicon was sent:', 'favicon.ico'); } }); }); nodePress.get('/stylesheets.css', function(request, response) { response.set("Content-Type", "text/css"); setBasicHeader(response); response.type("css"); if((parts["Cache"] == true) && (siteCSS != null)) { response.send(siteCSS); } else { siteCSS = fs.readFileSync(parts['Sitebase'] + 'css/final/final.css'); response.send(siteCSS); } }); nodePress.get('/scripts.js', function(request, response) { response.set("Content-Type", "text/javascript"); setBasicHeader(response); if((parts["Cache"] == true) && (siteScripts != null)) { response.send(siteScripts); } else { siteScripts = fs.readFileSync(parts['Sitebase'] + 'js/final/final.js', 'utf8'); response.send(siteScripts); } }); nodePress.get('/images/:image', function(request, response) { var options = { root: parts['Sitebase'] + 'images/', dotfiles: 'deny', headers: { 'x-timestamp': Date.now(), 'x-sent': true } }; response.set("Content-Type", "image/" + path.extname(request.params.image).substr(1)); setBasicHeader(response); response.sendFile(request.params.image, options, function(err) { if (err) { console.log(err); response.status(err.status).end(); } else { console.log('Image was sent:', request.params.image); } }); }); nodePress.get('/posts/blogs/:blog', function(request, response) { setBasicHeader(response); response.send(post("blogs", request.params.blog, "index")); }); nodePress.get('/posts/blogs/:blog/:post', function(request, response) { setBasicHeader(response); response.send(post("blogs", request.params.blog, request.params.post)); }); nodePress.get('/posts/news/:news', function(request, response) { setBasicHeader(response); response.send(post("news", request.params.news, "index")); }); nodePress.get('/posts/news/:news/:post', function(request, response) { setBasicHeader(response); response.send(post("news", request.params.news, request.params.post)); }); nodePress.get('/:page', function(request, response) { setBasicHeader(response); response.send(page(request.params.page)); }); </pre><div class="contentsignin">登入後複製</div></div> <p>这部分代码定义了实现 Web 服务器所需的所有路由。所有路由都运行 <code>setBasicHeader()</code> 函数来设置正确的标头值。所有针对页面类型的请求都会调用 <code>page()</code> 函数,而所有针对 post 类型页面的请求都会调用 <code>posts()</code> 函数。</p> <p><code class="inline">Content-Type</code> 的默认值为 HTML。因此,对于 CSS、JavaScript 和图像,<code class="inline">Content-Type</code> 显式设置为其适当的值。</p> <p>您还可以使用 <code>put</code>、<code>delete</code> 和 <code>post</code> REST 动词定义路由。这个简单的服务器仅使用 <code>get</code> 动词。</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// // Start the server. // var addressItems = parts['ServerAddress'].split(':'); var server = nodePress.listen(addressItems[2], function() { var host = server.address().address; var port = server.address().port; console.log('nodePress is listening at http://%s:%s', host, port); }); </pre><div class="contentsignin">登入後複製</div></div> <p>在定义所使用的不同函数之前要做的最后一件事是启动服务器。 server.json 文件包含 DNS 名称(此处为 <code>localhost</code>)和服务器的端口。解析后,服务器的 <code>listen()</code> 函数使用端口号来启动服务器。服务器端口打开后,脚本会记录服务器的地址和端口。</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// // Function: setBasicHeader // // Description: This function will set the basic header information // needed. // // Inputs: // response The response object // function setBasicHeader(response) { response.append("Cache-Control", "max-age=2592000, cache"); response.append("Server", "nodePress - a CMS written in node from Custom Computer Tools: http://customct.com."); } </pre><div class="contentsignin">登入後複製</div></div> <p>定义的第一个函数是 <code>setBasicHeader()</code> 函数。该函数设置响应头,告诉浏览器将页面缓存一个月。它还告诉浏览器该服务器是nodePress服务器。如果您需要任何其他标准标头值,您可以使用 <code>response.append()</code> 函数在此处添加它们。</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// // Function: page // // Description: This function processes a page request // // Inputs: // page The requested page // function page(page) { // // Process the given page using the standard layout. // return (processPage(parts["layout"], parts['Sitebase'] + "pages/" + page)); } </pre><div class="contentsignin">登入後複製</div></div> <p><code>page()</code> 函数将页面的布局模板以及页面在服务器上的位置发送到 <code>processPage()</code> 函数。</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// // Function: post // // Description: This function processes a post request // // Inputs: // type The type of post. // cat The category of the post. // post The requested post // function post(type, cat, post) { // // Process the post given the type and the post name. // return (processPage(parts["layout"], parts['Sitebase'] + "posts/" + type + "/" + cat + "/" + post)); } </pre><div class="contentsignin">登入後複製</div></div> <p><code>post()</code> 函数就像 <code>page()</code> 函数,不同之处在于帖子有更多项目来定义每个帖子。在这个系列的服务器中,一个post包含一个<code>type</code>、category,以及实际的<code>post</code>。类型为 <code>blogs</code> 或 <code>news</code>。类别是 <code>flatcms</code>。由于这些代表目录名称,因此您可以将它们设为您想要的任何名称。只需将命名与文件系统中的名称相匹配即可。</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// // Function: processPage // // Description: This function processes a page for the CMS. // // Inputs: // layout The layout to use for the page. // page Path to the page to render. // function processPage(layout, page) { // // Get the pages contents and add to the layout. // var context = {}; context = MergeRecursive(context, parts); context['content'] = figurePage(page); context['PageName'] = path.basename(page, path.extname(page)); // // Load page data. // if(fileExists(page + ".json")) { // // Load the page's data file and add it to the data structure. // context = MergeRecursive(context, JSON.parse(fs.readFileSync(page + '.json', 'utf8'))); } // // Process Handlebars codes. // var template = Handlebars.compile(layout); var html = template(context); // // Process all shortcodes. // html = processShortCodes(html); // // Run through Handlebars again. // template = Handlebars.compile(html); html = template(context); // // Return results. // return (html); } </pre><div class="contentsignin">登入後複製</div></div> <p><code>processPage()</code> 函数获取要呈现的页面内容的布局和路径。该函数首先创建 <code>parts</code> 全局变量的本地副本,并添加“contents”主题标签以及调用 <code>figurePage()</code> 函数的结果。然后,它将 <code>PageName</code> 哈希值设置为页面名称。</p> <p>然后,该函数使用 Handlebars 将页面内容编译到布局模板。之后, <code>processShortCodes()</code> 函数将展开页面上定义的所有短代码。然后,Handlebars 模板引擎再次检查代码。然后浏览器接收结果。</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// // Function: processShortCodes // // Description: This function takes a string and // processes all of the shortcodes in // the string. // // Inputs: // content String to process // function processShortCodes(content) { // // Create the results variable. // var results = ""; // // Find the first match. // var scregFind = /\-\[([^\]]*)\]\-/i; var match = scregFind.exec(content); if (match != null) { results += content.substr(0,match.index); var scregNameArg = /(\w+)(.*)*/i; var parts = scregNameArg.exec(match[1]); if (parts != null) { // // Find the closing tag. // var scregClose = new RegExp("\\-\\[\\/" + parts[1] + "\\]\\-"); var left = content.substr(match.index + 4 + parts[1].length); var match2 = scregClose.exec(left); if (match2 != null) { // // Process the enclosed shortcode text. // var enclosed = processShortCodes(content.substr(match.index + 4 + parts[1].length, match2.index)); // // Figure out if there were any arguments. // var args = ""; if (parts.length == 2) { args = parts[2]; } // // Execute the shortcode. // results += shortcodes[parts[1]](args, enclosed); // // Process the rest of the code for shortcodes. // results += processShortCodes(left.substr(match2.index + 5 + parts[1].length)); } else { // // Invalid shortcode. Return full string. // results = content; } } else { // // Invalid shortcode. Return full string. // results = content; } } else { // // No shortcodes found. Return the string. // results = content; } return (results); } </pre><div class="contentsignin">登入後複製</div></div> <p><code>processShortCodes()</code> 函数将网页内容作为字符串并搜索所有短代码。短代码是类似于 HTML 标签的代码块。一个例子是:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>-[box]- <p>This is inside a box</p> -[/box]- </pre><div class="contentsignin">登入後複製</div></div> <p>此代码在 HTML 段落周围有一个 <code>box</code> 的简码。其中 HTML 使用 <code><</code> 和 </code>>></code>,短代码使用 <code>-[</code> 和 </code>>]-</code>。在名称后面,可以包含或不可以包含包含短代码参数的字符串。</p> <p><code>processShortCodes()</code> 函数查找短代码,获取其名称和参数,找到末尾以获取内容,处理短代码的内容,使用参数和内容执行短代码,将结果添加到完成中页面,并在页面的其余部分搜索下一个短代码。循环是通过递归调用函数来执行的。</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// // Define the shortcodes function array. // var shortcodes = { 'box': function(args, inside) { return ("<div class='box'>" + inside + "</div>"); }, 'Column1': function(args, inside) { return ("<div class='col1'>" + inside + "</div>"); }, 'Column2': function(args, inside) { return ("<div class='col2'>" + inside + "</div>"); }, 'Column1of3': function(args, inside) { return ("<div class='col1of3'>" + inside + "</div>"); }, 'Column2of3': function(args, inside) { return ("<div class='col2of3'>" + inside + "</div>"); }, 'Column3of3': function(args, inside) { return ("<div class='col3of3'>" + inside + "</div>"); }, 'php': function(args, inside) { return ("<div class='showcode'><pre type='syntaxhighlighter' class='brush: php'>" + inside + "</pre><div class="contentsignin">登入後複製</div></div></div>"); }, 'js': function(args, inside) { return ("<div class='showcode'><div class="code" style="position:relative; padding:0px; margin:0px;"><pre type='syntaxhighlighter' class='brush: javascript'>" + inside + "</pre><div class="contentsignin">登入後複製</div></div></div>"); }, 'html': function(args, inside) { return ("<div class='showcode'><div class="code" style="position:relative; padding:0px; margin:0px;"><pre type='syntaxhighlighter' class='brush: html'>" + inside + "</pre><div class="contentsignin">登入後複製</div></div></div>"); }, 'css': function(args, inside) { return ("<div class='showcode'><div class="code" style="position:relative; padding:0px; margin:0px;"><pre type='syntaxhighlighter' class='brush: css'>" + inside + "</pre><div class="contentsignin">登入後複製</div></div></div>"); } }; </pre> <p>下一节定义 <code>shortcodes</code> json 结构,该结构定义与其函数关联的短代码的名称。所有短代码函数都接受两个参数:<code>args</code> 和 <code>inside</code>。 <code>args</code> 是名称和空格之后、标签结束之前的所有内容。 <code>inside</code> 是开始和结束短代码标记包含的所有内容。这些功能是基本功能,但您可以创建一个短代码来执行您能在 JavaScript 中想到的任何功能。</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// // Function: figurePage // // Description: This function figures the page type // and loads the contents appropriately // returning the HTML contents for the page. // // Inputs: // page The page to load contents. // function figurePage(page) { var result = ""; if (fileExists(page + ".html")) { // // It's an HTML file. Read it in and send it on. // result = fs.readFileSync(page + ".html"); } else if (fileExists(page + ".amber")) { // // It's a jade file. Convert to HTML and send it on. I // am still using the amber extension for compatibility // to goPress. // var jadeFun = jade.compileFile(page + ".amber", {}); // Render the function var result = jadeFun({}); } else if (fileExists(page + ".md")) { // // It's a markdown file. Convert to HTML and send // it on. // result = marked(fs.readFileSync(page + ".md").toString()); // // This undo marked's URI encoding of quote marks. // result = result.replace(/\&quot\;/g,"\""); } return (result); } </pre><div class="contentsignin">登入後複製</div></div> <p><code>figurePage()</code> 函数接收服务器上页面的完整路径。然后,此函数根据扩展名测试它是否为 HTML、Markdown 或 Jade 页面。我仍然在 Jade 中使用 .amber,因为那是我在 goPress 服务器上使用的库。所有 Markdown 和 Jade 内容都会先转换为 HTML,然后再传递给调用例程。由于 Markdown 处理器将所有引号翻译为 <code>"</code>,因此我在传回之前将它们翻译回来。</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// // Function: fileExists // // Description: This function returns a boolean true if // the file exists. Otherwise, false. // // Inputs: // filePath Path to a file in a string. // function fileExists(filePath) { try { return fs.statSync(filePath).isFile(); } catch (err) { return false; } } </pre><div class="contentsignin">登入後複製</div></div> <p><code>fileExists()</code> 函数是 <code>fs.exists()</code> 函数的替代品,该函数曾经是 Node.js 的 <code>fs</code> 库的一部分。它使用 <code>fs.statSync()</code> 函数来尝试获取文件的状态。如果发生错误,则会返回 <code>false</code>。否则,返回 <code>true</code>。</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// // Function: MergeRecursive // // Description: Recursively merge properties of two objects // // Inputs: // obj1 The first object to merge // obj2 The second object to merge // function MergeRecursive(obj1, obj2) { for (var p in obj2) { try { // Property in destination object set; update its value. if (obj2[p].constructor == Object) { obj1[p] = MergeRecursive(obj1[p], obj2[p]); } else { obj1[p] = obj2[p]; } } catch (e) { // Property in destination object not set; create it and set its value. obj1[p] = obj2[p]; } } return obj1; } </pre><div class="contentsignin">登入後複製</div></div> <p>最后一个函数是 <code>MergeRecursive()</code> 函数。它将第二个传递对象复制到第一个传递对象中。在添加特定于页面的部分之前,我利用它将主 <code>parts</code> 全局变量复制到本地副本中。</p> <h3 id="本地运行">本地运行</h3> <p>保存文件后,您可以使用以下命令运行服务器:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>node nodePress.js </pre><div class="contentsignin">登入後複製</div></div> <p>或者,您可以使用 package.json 文件中的 <code class="inline">npm</code> 脚本。您可以像这样运行 npm 脚本:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>npm start </pre><div class="contentsignin">登入後複製</div></div> <p>这将运行 package.json 文件内的 <code>start</code> 脚本。</p> <p><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/164/169372039225694.jpg" class="lazy" alt="建立內容管理系統:nodePress"></p> <p>将您的网络浏览器指向 <code>http://localhost:8080</code>,您将看到上面的页面。您可能已经注意到我在主页上添加了更多测试代码。对页面的所有更改都包含在本教程的下载中。它们大多只是一些小的调整,以更全面地测试功能并适应使用不同库的任何差异。最显着的区别是 Jade 库不使用 <code class="inline">$</code> 来命名变量,而 Amber 则使用。</p> <h2 id="结论">结论</h2> <p>现在,您在 Go 和 Node.js 中拥有完全相同的平面文件系统 CMS。这只是您可以使用此平台构建的内容的表面。尝试并尝试新事物。这是创建您自己的网络服务器的最佳部分。</p>

以上是建立內容管理系統:nodePress的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何創建和發布自己的JavaScript庫? 如何創建和發布自己的JavaScript庫? Mar 18, 2025 pm 03:12 PM

文章討論了創建,發布和維護JavaScript庫,專注於計劃,開發,測試,文檔和促銷策略。

如何在瀏覽器中優化JavaScript代碼以進行性能? 如何在瀏覽器中優化JavaScript代碼以進行性能? Mar 18, 2025 pm 03:14 PM

本文討論了在瀏覽器中優化JavaScript性能的策略,重點是減少執行時間並最大程度地減少對頁面負載速度的影響。

前端熱敏紙小票打印遇到亂碼問題怎麼辦? 前端熱敏紙小票打印遇到亂碼問題怎麼辦? Apr 04, 2025 pm 02:42 PM

前端熱敏紙小票打印的常見問題與解決方案在前端開發中,小票打印是一個常見的需求。然而,很多開發者在實...

如何使用瀏覽器開發人員工具有效調試JavaScript代碼? 如何使用瀏覽器開發人員工具有效調試JavaScript代碼? Mar 18, 2025 pm 03:16 PM

本文討論了使用瀏覽器開發人員工具的有效JavaScript調試,專注於設置斷點,使用控制台和分析性能。

如何使用源地圖調試縮小JavaScript代碼? 如何使用源地圖調試縮小JavaScript代碼? Mar 18, 2025 pm 03:17 PM

本文說明瞭如何使用源地圖通過將其映射回原始代碼來調試JAVASCRIPT。它討論了啟用源地圖,設置斷點以及使用Chrome DevTools和WebPack之類的工具。

誰得到更多的Python或JavaScript? 誰得到更多的Python或JavaScript? Apr 04, 2025 am 12:09 AM

Python和JavaScript開發者的薪資沒有絕對的高低,具體取決於技能和行業需求。 1.Python在數據科學和機器學習領域可能薪資更高。 2.JavaScript在前端和全棧開發中需求大,薪資也可觀。 3.影響因素包括經驗、地理位置、公司規模和特定技能。

開始使用Chart.js:PIE,DONUT和BUBBLE圖表 開始使用Chart.js:PIE,DONUT和BUBBLE圖表 Mar 15, 2025 am 09:19 AM

本教程將介紹如何使用 Chart.js 創建餅圖、環形圖和氣泡圖。此前,我們已學習了 Chart.js 的四種圖表類型:折線圖和條形圖(教程二),以及雷達圖和極地區域圖(教程三)。 創建餅圖和環形圖 餅圖和環形圖非常適合展示某個整體被劃分為不同部分的比例。例如,可以使用餅圖展示野生動物園中雄獅、雌獅和幼獅的百分比,或不同候選人在選舉中獲得的投票百分比。 餅圖僅適用於比較單個參數或數據集。需要注意的是,餅圖無法繪製值為零的實體,因為餅圖中扇形的角度取決於數據點的數值大小。這意味著任何占比為零的實體

初學者的打字稿,第2部分:基本數據類型 初學者的打字稿,第2部分:基本數據類型 Mar 19, 2025 am 09:10 AM

掌握了入門級TypeScript教程後,您應該能夠在支持TypeScript的IDE中編寫自己的代碼,並將其編譯成JavaScript。本教程將深入探討TypeScript中各種數據類型。 JavaScript擁有七種數據類型:Null、Undefined、Boolean、Number、String、Symbol(ES6引入)和Object。 TypeScript在此基礎上定義了更多類型,本教程將詳細介紹所有這些類型。 Null數據類型 與JavaScript一樣,TypeScript中的null

See all articles