gulp gulp-markdown gulp-html-extend ASP.NET Core
A Markdown
server is a web server which can convert markdown files into HTML.
▋.NET Core 2.1.300
▋gulp 3.9.1
▋gulp-markdown 3.0.0
▋gulp-html-extend 1.1.6
▋gulp-watch 5.0.1
▋marked 0.4.0
Before we
build the website, lets take a quick look at the gulp packages.
▋gulp-markdown
Convert Markdown to HTML with marked, which is a markdown
parser and compiler.
Basic usage is as following, results in converting the
content of README.md as HTML and copy to dist/README.md
const gulp = require('gulp');
const markdown = require('gulp-markdown');
gulp.task('default', () =>
gulp.src('README.md')
.pipe(markdown())
.pipe(gulp.dest('dist'));
);
const marked = require('marked');
// Set options
marked.setOptions({
renderer: new marked.Renderer(),
pedantic: false,
gfm: true,
tables: true,
breaks: false,
sanitize: false,
smartLists: true,
smartypants: false,
xhtml: false
});
gulp.task('md', function () {
return gulp.src('README.md')
.pipe(markdown(marked))
.pipe(gulp.dest('dist'));
})
▋gulp-html-extend
However, the HTML after
converted doesn’t have default HTML tags such as <html>, <head>,
<body>.
We do need a default HTML template
that can be put the converted-markdown content inside. Thaz why we need gulp-html-extend.
The usage is similar with the
template tag in Django.
Create a template page like
this,
▋master.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" >
<title><!-- @@var title --></title>
<!-- @@placeholder=head -->
</head>
<body>
<!-- @@placeholder=body -->
</body>
</html>
@@var [=] <variableName> preservers the position for a value for the variable.
@@placeholder [=] <blockName> preservers a block to put the real content inside.
▋my-content.html
Now we can make a content
html as following,
<!--
@@master= ./master.html {"title":"Demo"}-->
<!--
@@block=head-->
<meta name="author" content="JB" />
<!--
@@close-->
<!--
@@block=body-->
<h2>gulp-html-extend demo<h2>
<!--
@@close-->
@@master [=] path [jsonString] defines the
relative path of the master page and set the value for variables by JSON.
Between @@block [=]
blockName and @@close
is the content for the block in master page.
▋gulp-html-extend
gulp.task('extend', function () {
return gulp.src('content.html')
.pipe(extender({
annotations: true,
verbose: false
}))
.pipe(gulp.dest('dist'))
});
Which will result in:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<title>Demo</title>
<!-- start head -->
<meta name="author" content="JB" />
<!-- end head -->
</head>
<body>
<!-- start body -->
<h2>gulp-html-extend demo</h2>
<!-- end body -->
</body>
</html>
▋Create website and install packages
Use the following donet CLI commands to create a website,
$ dotnet new
mvc --name my-mdserver.web
$ dotnet new
sln --name my-mdserver
$ dotnet sln
my-mdserver.sln add
my-mdserver-web/my-mdserver-web.csproj
$ dotnet
restore
$ dotnet build
$ npm init
Install the npm packages and create a gulp file
$ npm install
gulp --save-dev
$ npm install
marked --save-dev
$ npm install
gulp-markdown --save-dev
$ npm install
gulp-html-extend --save-dev
$ npm install
gulp-watch --save-dev
$ cd
my-mdserver.web
$ echo
nul>gulpfile.js
▋gulpfile.js
▋requires
// Include
gulp
const gulp = require('gulp');
const rename = require('gulp-rename');
const watch = require('gulp-watch');
const extender = require('gulp-html-extend')
const markdown = require('gulp-markdown');
const marked = require('marked');
var mdFilePath = "./wwwroot/markdown/";
▋Task for gulp-markdown
// Set options
marked.setOptions({
renderer: new marked.Renderer(),
highlight: function (code) {
return require('highlight.js').highlightAuto(code).value;
},
pedantic: false,
gfm: true,
tables: true,
breaks: false,
sanitize: false,
smartLists: true,
smartypants: false,
xhtml: false
});
//Convert MD
to HTML
gulp.task('md', function () {
return gulp.src(mdFilePath + '**/*.md')
.pipe(markdown(marked))
.pipe(rename({
extname: ".html"
}))
.pipe(gulp.dest(function (file) {
return file.base;
}));
})
The destination directory is same as the original
Markdown file, but the converted file’s extension name will be .html.
▋Task for gulp-html-extend
This is the main callback task for watching changes of
any Markdown file.
Therefore, we put the md task as a dependency
of this task, extend.
//Merge the
master and extend pages
gulp.task('extend', ['md'], function () {
return gulp.src(mdFilePath + '**/*.html')
.pipe(extender({
annotations: true,
verbose: false
}))
.pipe(gulp.dest(function (file) {
return file.base;
}));
});
▋Task for watching Markdown
files
In the last, we use gulp-watch to watch the *.md files.
Notice that the watch function in gulp.js doesn’t
support watching new/deleted files
in run-time. So we use gulp-watch instead.
gulp.task('watch', function () {
// gulp.watch(mdFilePath + '**/*.md', ['extend']); //Not
support new/delete files
return watch(mdFilePath + '**/*.md', function(){
gulp.start("extend");
});
});
//Default
tasks
gulp.task('default', ["watch"]);
▋Start the service
$ dotnet build
$ gulp
▋Demo
▋fs.watch roblem
While I ran the gulp-watch in a virtual machine, sometimes
the watch listener caused the following error,
[09:55:30] Error: watch …\wwwroot\markdown\新增資料夾 (2) EBUSY
at _errnoException (util.js:1003:13)
at
FSWatcher.start (fs.js:1397:19)
at
Object.fs.watch (fs.js:1423:11)
at
createFsWatchInstance
This is because that the maximum number for listening document
is not the same in every environment or OS. So when you are using VM, follow
the post in Stackoverflow
to increase this max number, I shorten the answer as following,
Cmd in Windows:
$ echo
fs.inotify.max_user_watches=524288
Unix shell:
$ echo
fs.inotify.max_user_watches=582222 | sudo tee -a /etc/sysctl.conf &&
sudo sysctl -p