是否有一些 gulp 插件可以让它执行静态站点生成器的功能?
Posted
技术标签:
【中文标题】是否有一些 gulp 插件可以让它执行静态站点生成器的功能?【英文标题】:Is there some gulp plugin that lets it perform the function of a static site generator? 【发布时间】:2014-06-07 06:42:53 【问题描述】:我使用了一堆静态站点生成器,但 gulp 是一种更好的方法,因为它非常模块化。我想知道是否有一个插件可以执行静态站点生成器的某些功能。在我看来,所缺少的只是将目录中的文件转换为 json 数据结构,以便在网站上的菜单中使用。
【问题讨论】:
顺便说一句:我正在编写一组 Gulp 插件和一个 Yeoman 生成器,以使其易于使用。它被称为 Stratic:github.com/strugee/generator-stratic。完成后我会留下正确的答案。 【参考方案1】:如果您只想生成一个 .json 结构并使用 Gulp 将其添加到文件中,您可以通过以下几种方式之一执行此操作。前两个使用纯 Gulp 技术:
您可以使用through
或through2
编写流插件,基本上必须一次建立一个文件的数据结构,然后在第二次操作中创建(即push()
或queue()
) 末尾的文件
您可以使用Highland 管道将.reduce()
文件传输到数据结构,然后将.map()
结果传输到文件中,也许可以使用原始流执行.merge()
在这两种情况下,您都需要生成的新 vinyl
文件具有适当的 .base
和 .path
,您的插件 实际上并不知道,因为该文件你正在创建还不存在。因此,您的代码必须构成一个虚假的绝对路径,以便gulp.dest()
将其放置在正确的位置。
第三个技巧是写一个Metalsmith 插件,看起来像这样:
function generate_json(files, smith, done)
var menu = ;
Object.keys(files).forEach(function(path)
var file = files[path];
if (path.slice(-5)===".html")
menu[path] = ... // whatever you want to store about `file`
);
files["path/to/menu.json"] = contents: new Buffer(JSON.stringify(menu)) ;
done();
虽然没有很多比其他方法所需的代码短,但您需要了解的内容少得多才能正确执行。只要确保如果您有错误,请致电done(err)
以传递错误。
如果您想将此插件与 Gulp 管道相结合,您可以使用 Gulpsmith 将其包装起来:
gulp.src(...)
.pipe( things() )
.pipe( gulpsmith().use(generate_json) )
.pipe( other_stuff() )
.pipe( gulp.dest(...);
Gulp 确实比 Metalsmith 具有某些优势。遗憾的是,易于编写插件不是其中之一。从 Gulp 插件创建新文件比它应该的更难,正确的错误处理也是如此。流式传输方法与需要跨文件操作的静态站点的性质之间也存在严重的阻抗不匹配。
例如,如果您希望在创建后将菜单嵌入到每个 .html 页面中,您将需要一个更复杂的 Gulp 插件,因为当您的插件“看到”所有文件,它们将“流向下游”,否则您将不得不抓住它们,然后在完成后再次将它们流式传输。在 Metalsmith 插件中,您只需在生成菜单后添加第二个循环,以再次返回文件以插入数据,就地。你不需要做任何事情来传递你没有做任何事情的文件。
对于这类任务,Metalsmith 插件 API 无疑优于 Gulp。但是对于可以单独处理流文件的任务,请使用现有的 Gulp 插件。
基本上,Metalsmith 是静态站点生成器的 Gulp,而 Gulp 是流式构建系统的 Gulp。您可以使用 Gulpsmith 结合两者的优势。
(顺便说一下,根据您的实际任务,您可能会发现一些现有的 Metalsmith 插件可以完成全部或部分工作。例如,metalsmith-collections
插件为匹配某些模式的文件创建索引,有一个 metalsmith-title
将 HTML 标头提取到标题属性等)
【讨论】:
真的很好的细分和很好的例子。谢谢! 好文章!另一个关于使用 Gulp 作为静态站点生成器的不错的博客可以找到 here【参考方案2】:是的,你可以在 gulp 中进行静态生成。
您可能需要的插件比您想象的要少。计数可能会向下舍入为零。
考虑一下你可以用 gulp 做什么而不用插件:
var gulp = require('gulp'),
browserify = require('browserify');
gulp.task('browserify', function(callback)
browserify('app.js').bundle()
.pipe(fs.createWriteStream('dist/app.js')
.on('close', callback); // why? read on...
);
Too many gulp plugins don't need to exist。他们将一些原始模块改编为gulp.src
和gulp.dest
之间使用的乙烯基对象流,但乙烯基对象流不是强制性的。
需要模块 X 为您做一些静态生成吗?将callback
作为任务函数的参数,并将其与参数一起传递给 X。通常情况下,它是一条线:require
-ing 一个插件只会让你的代码更长。
即使对于最好描述为“读取所有内容,在内存中处理并写入一次”的工作流程的那些部分,您也可以使用 through2.obj 来转换乙烯基对象或使用 gulp-filter 将它们剔除。 Gulp 插件(或者,更糟糕的是,gulpsmith 的 metalsmith 插件)是最后的手段。
var gulp = require('gulp'),
filter = require('gulp-filter'),
through2 = require('through2');
gulp.task('generate-assets', function()
return gulp.src('path/to/your/content/and/templates/**')
.pipe(filter(shouldFileSurvive))
.pipe(through2.obj(makeFileDifferent))
.pipe(gulp.dest('dist/'));
);
注意:如果您不回拨,则必须返回最终pipe
的结果。否则,gulp 会认为你的任务是同步的,而不是在启动依赖任务之前等待。
如果最终管道返回正常流而不是 gulp.dest
,则进行回调(参见第一个示例)直到 b59182c7 登陆。
【讨论】:
【参考方案3】:我一直在写这样一个插件,这里是gulp-static-site
。查看其他两个答案,我会说它的功能介于 vanilla gulp 和 gulpsmith
之间。
Gulp-filetree
主要功能确实是树状数据结构的计算,由gulp-filetree
完成。它逐渐建立一棵树,直到流结束。然后使用.tree
属性重新发送每个文件(乙烯基对象)。
查看tree.js
以获取有关该数据结构的更多信息。
Gulp-static-site
这个插件接受一个 HTML 文件流,通过gulp-filetree
将它们发送到一个玉模板,该模板添加了一个带有目录树菜单和文件内容的基本布局。
在此处查看主管道。 https://github.com/0x01/gulp-static-site/blob/master/index.js#L146 (正如你所看到的,它不是最漂亮的,但还可以。必须删除 Markdown 转换,因为它可以在插件外部的 gulp 中完成。可能同样的论点适用于其他东西......)
问:这与gulpsmith
有何关系?
Gulpsmith 绝对看起来强大而完整,如果我在最初编写此代码时就知道它,我可能会使用它。
话虽如此;这个插件简单、轻量并且有一个小的代码库。我认为很容易理解它的作用并根据自己的喜好进行更改,当然欢迎拉取请求:-)
如果还有什么不清楚的,请提出问题或在这里告诉我,谢谢
【讨论】:
gulp-static-site
解决了 @garth-kidd 的回答没有解决 metalsmith / gulpsmith 的哪些问题?
可能当时我没有注意到或将金属匠与 Wintersmith 混淆(我不喜欢)。无论如何,我当然不知道gulpsmith
。现在看了,觉得还蛮好看的。这个插件当然更基本,可以推测,因为我更像是一个自下而上的编码器。它也是非常轻量级和简单的可破解代码;这已经做了很多。我会更新答案,谢谢!以上是关于是否有一些 gulp 插件可以让它执行静态站点生成器的功能?的主要内容,如果未能解决你的问题,请参考以下文章
Gulp插件之run-sequence控制任务顺序或者并行执行