<p>Sie haben mit Go erfolgreich ein Flatfile-Content-Management-System (CMS) erstellt. Der nächste Schritt besteht darin, die gleiche Idee zu übernehmen und einen Webserver mit Node.js zu erstellen. Ich zeige Ihnen, wie Sie die Bibliothek laden, den Server erstellen und den Server ausführen. </p>
<p>Dieses CMS verwendet die Site-Datenstruktur, die im ersten Tutorial „Erstellen eines CMS: Struktur und Stil“ eingeführt wurde. Laden Sie also diese Grundstruktur herunter und installieren Sie sie in einem neuen Verzeichnis. </p>
<h2>Knoten und Knotenbibliotheken abrufen</h2>
<p>Der einfachste Weg, Node.js auf einem Mac zu installieren, ist die Verwendung von Homebrew. Wenn Sie Homebrew noch nicht installiert haben, zeigt Ihnen das Tutorial „Homebrew Revealed: The Ultimate Package Manager for OS X“, wie Sie es installieren. </p>
<p>Um Node.js mit Homebrew zu installieren, geben Sie den folgenden Befehl im Terminal ein: </p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:shell;toolbal:false;">brew install node
</pre><div class="contentsignin">Nach dem Login kopieren</div></div>
<p>Nach Abschluss sind die Node- und npm-Befehle vollständig auf Ihrem Mac installiert. Befolgen Sie für alle anderen Plattformen die Anweisungen auf der Node.js-Website. </p>
<p>Bitte beachten Sie: Viele Paketmanager installieren derzeit Node.js Version 0.10. Für dieses Tutorial wird davon ausgegangen, dass Sie Version 5.3 oder höher haben. Sie können Ihre Version überprüfen, indem Sie Folgendes eingeben: </p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:shell;toolbal:false;">node --version
</pre><div class="contentsignin">Nach dem Login kopieren</div></div>
Der Befehl <p><code class="inline">node</code> 命令运行 JavaScript 解释器。 <code class="inline">npm</code> ist der Paketmanager für Node.js und wird zum Installieren neuer Bibliotheken, zum Erstellen neuer Projekte und zum Ausführen von Projektskripten verwendet. Envato Tuts+ bietet viele tolle Tutorials und Kurse zu Node.js und NPM. </p>
<p>Um die Bibliotheken des Webservers zu installieren, müssen Sie den folgenden Befehl im Programm Terminal.app oder iTerm.app ausführen: </p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:shell;toolbal: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">Nach dem Login kopieren</div></div>
<p>Express ist eine Plattform zur Entwicklung von Webanwendungen. Es ähnelt der goWeb-Bibliothek in Go. Lenker ist eine Template-Engine zum Erstellen von Seiten. Moment ist eine Bibliothek zum Arbeiten mit Datumsangaben. Marked ist ein großartiger Markdown-zu-HTML-Konverter in JavaScript. Jade ist eine HTML-Kurzschriftsprache, die die Erstellung von HTML erleichtert. Morgan ist eine Middleware-Bibliothek für Express, die Apache-Standardprotokolldateien generiert. </p>
<p>Eine andere Möglichkeit, die Bibliothek zu installieren, besteht darin, die Quelldateien für dieses Tutorial herunterzuladen. Geben Sie nach dem Herunterladen und Entpacken im Hauptverzeichnis ein: </p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:shell;toolbal:false;">npm --install
</pre><div class="contentsignin">Nach dem Login kopieren</div></div>
<p>Dadurch wird alles installiert, was zum Erstellen dieses Projekts erforderlich ist. </p>
<h2>nodePress.js</h2>
<p>Jetzt können Sie mit der Erstellung des Servers beginnen. Erstellen Sie im obersten Verzeichnis Ihres Projekts eine Datei mit dem Namen „nodePress.js“, öffnen Sie sie im Editor Ihrer Wahl und beginnen Sie mit dem Hinzufügen des folgenden Codes. Ich erkläre den Code, den ich in die Datei eingefügt habe. </p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:javascript;toolbal: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">Nach dem Login kopieren</div></div>
<p>Der Servercode beginnt mit der Initialisierung aller Bibliotheken, die zum Erstellen des Servers verwendet wurden. Bibliotheken ohne Annotationen mit URLs sind interne Node.js-Bibliotheken. </p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:javascript;toolbal: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">Nach dem Login kopieren</div></div>
<p>Als nächstes richte ich alle globalen Variablen und die Bibliothekskonfiguration ein. Die Verwendung globaler Variablen ist nicht die beste Vorgehensweise beim Software-Design, aber sie funktioniert und hilft bei der schnellen Entwicklung. </p>
<p><code class="inline">parts</code> Die Variable ist ein Array von Hashes, das alle Teile der Webseite enthält. Jede Seite verweist auf den Inhalt dieser Variablen. Es beginnt mit dem Inhalt der Datei server.json oben im Serververzeichnis. </p>
<p>Ich habe dann die Informationen in der Datei server.json verwendet, um den vollständigen Pfad zum Verzeichnis <code class="inline">styles</code> 和 <code class="inline">layouts</code> für diese Site zu erstellen. </p>
<p>Dann setzen Sie drei Variablen auf leere Werte: <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> Wenn die Variable falsch ist, werden die Elemente bei jeder Anfrage erneut gelesen. </p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:javascript;toolbal: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">Nach dem Login kopieren</div></div>
<p>Dieser Codeblock wird verwendet, um die Marked-Bibliothek für die Generierung von HTML aus Markdown zu konfigurieren. Meistens schalte ich die Unterstützung für Tabellen und SmartLists ein. </p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:javascript;toolbal: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">Nach dem Login kopieren</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> Variablen laden außerdem Abschnitte in den Verzeichnissen <code class="inline">styles</code> und <code class="inline">layout</code>. Jede Datei im Verzeichnis </p> innerhalb des Verzeichnisses <code class="inline">site</code> wird auch in die globale Variable <p> geladen. Der Dateiname ohne Erweiterung ist der Name, der zum Speichern des Dateiinhalts verwendet wird. Diese Namen werden im Makro „Lenker“ erweitert. <code class="inline">save</code>、<code class="inline">date</code> 和 <code class="inline">cdate</code>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:javascript;toolbal: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">Nach dem Login kopieren</div></div>
</p>Der nächste Codeabschnitt definiert den Handler-Helfer, den ich für die Verwendung im Webserver definiert habe: <p>. Der Speicherassistent ermöglicht das Erstellen von Variablen innerhalb der Seite. Diese Version unterstützt die goPress-Version, bei der Name und Wert des Parameters durch „|“ getrennt werden. Sie können das Speichern auch über zwei Parameter festlegen. Zum Beispiel: </p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:plaintext;toolbal:false;">{{save "name|Richard Guay"}}
{{save "newName" "Richard Guay"}}
Name is: {{name}}
newName is: {{newName}}
</pre><div class="contentsignin">Nach dem Login kopieren</div></div>
🎜Dies führt zum gleichen Ergebnis. Ich bevorzuge den zweiten Ansatz, aber die Lenkerbibliothek in Go lässt nicht mehrere Argumente zu. 🎜
<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:javascript;toolbal:false;">//
// Create and configure the server.
//
var nodePress = express();
//
// Configure middleware.
//
nodePress.use(morgan('combined'))
</pre><div class="contentsignin">Nach dem Login kopieren</div></div>
<p>现在,代码创建一个 Express 实例来配置实际的服务器引擎。 <code>nodePress.use()</code> 函数设置中间件软件。中间件是在每次调用服务器时提供服务的任何代码。在这里,我设置了 Morgan.js 库来创建正确的服务器日志输出。</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:javascript;toolbal: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">Nach dem Login kopieren</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:javascript;toolbal: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">Nach dem Login kopieren</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:javascript;toolbal: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">Nach dem Login kopieren</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:javascript;toolbal: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">Nach dem Login kopieren</div></div>
<p><code>page()</code> 函数将页面的布局模板以及页面在服务器上的位置发送到 <code>processPage()</code> 函数。</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:javascript;toolbal: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">Nach dem Login kopieren</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:javascript;toolbal: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">Nach dem Login kopieren</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:javascript;toolbal: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">Nach dem Login kopieren</div></div>
<p><code>processShortCodes()</code> 函数将网页内容作为字符串并搜索所有短代码。短代码是类似于 HTML 标签的代码块。一个例子是:</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:html;toolbal:false;">-[box]-
<p>This is inside a box</p>
-[/box]-
</pre><div class="contentsignin">Nach dem Login kopieren</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:javascript;toolbal: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">Nach dem Login kopieren</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">Nach dem Login kopieren</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">Nach dem Login kopieren</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">Nach dem Login kopieren</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:javascript;toolbal: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(/\"\;/g,"\"");
}
return (result);
}
</pre><div class="contentsignin">Nach dem Login kopieren</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:javascript;toolbal: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">Nach dem Login kopieren</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:javascript;toolbal: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">Nach dem Login kopieren</div></div>
<p>最后一个函数是 <code>MergeRecursive()</code> 函数。它将第二个传递对象复制到第一个传递对象中。在添加特定于页面的部分之前,我利用它将主 <code>parts</code> 全局变量复制到本地副本中。</p>
<h3>本地运行</h3>
<p>保存文件后,您可以使用以下命令运行服务器:</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:shell;toolbal:false;">node nodePress.js
</pre><div class="contentsignin">Nach dem Login kopieren</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:shell;toolbal:false;">npm start
</pre><div class="contentsignin">Nach dem Login kopieren</div></div>
<p>这将运行 package.json 文件内的 <code>start</code> 脚本。</p>
<p><img src="https://img.php.cn/upload/article/000/000/164/169372039225694.jpg" alt="Erstellen Sie ein Content-Management-System: nodePress"></p>
<p>将您的网络浏览器指向 <code>http://localhost:8080</code>,您将看到上面的页面。您可能已经注意到我在主页上添加了更多测试代码。对页面的所有更改都包含在本教程的下载中。它们大多只是一些小的调整,以更全面地测试功能并适应使用不同库的任何差异。最显着的区别是 Jade 库不使用 <code class="inline">$</code> 来命名变量,而 Amber 则使用。</p>
<h2>结论</h2>
<p>现在,您在 Go 和 Node.js 中拥有完全相同的平面文件系统 CMS。这只是您可以使用此平台构建的内容的表面。尝试并尝试新事物。这是创建您自己的网络服务器的最佳部分。</p>
Das obige ist der detaillierte Inhalt vonErstellen Sie ein Content-Management-System: nodePress. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!