UNPKG

meblog

Version:

A simple blog engine for personal blogging

323 lines (322 loc) 13.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const gulp_1 = tslib_1.__importDefault(require("gulp")); const path_1 = tslib_1.__importDefault(require("path")); const del_1 = tslib_1.__importDefault(require("del")); const browser_sync_1 = tslib_1.__importDefault(require("browser-sync")); const gulp_clean_css_1 = tslib_1.__importDefault(require("gulp-clean-css")); const gulp_autoprefixer_1 = tslib_1.__importDefault(require("gulp-autoprefixer")); const gulp_sass_1 = tslib_1.__importDefault(require("gulp-sass")); const gulp_sourcemaps_1 = tslib_1.__importDefault(require("gulp-sourcemaps")); const gulplog_1 = tslib_1.__importDefault(require("gulplog")); const ansi_colors_1 = tslib_1.__importDefault(require("ansi-colors")); const i18n_1 = tslib_1.__importDefault(require("i18n")); const FilesSource_1 = tslib_1.__importDefault(require("./source/FilesSource")); const TemplateRenderer_1 = tslib_1.__importDefault(require("./template/TemplateRenderer")); const SampleGenerator_1 = tslib_1.__importDefault(require("./SampleGenerator")); const RssGenerator_1 = tslib_1.__importDefault(require("./RssGenerator")); const ConfigHolder_1 = tslib_1.__importDefault(require("./ConfigHolder")); const emittery_1 = tslib_1.__importDefault(require("emittery")); const StringUtils_1 = tslib_1.__importDefault(require("./util/StringUtils")); const GulpUtils_1 = tslib_1.__importDefault(require("./util/GulpUtils")); const DEV_PORT = 3000; const DEFAULT_LOCALE = 'en'; class SiteGenerator extends ConfigHolder_1.default { dataSource; renderer; generator; eventEmitter; browserSync; args; constructor(config, args) { super(config); this.args = args; this.generator = new SampleGenerator_1.default(); this.eventEmitter = new emittery_1.default(); this.browserSync = browser_sync_1.default.create('meblog'); this.registerEvents(); this.setupI18n(); } setupI18n() { if (!this.config.defaultLocale) { this.config.defaultLocale = DEFAULT_LOCALE; } let { locales = [] } = this.config; if (typeof locales === 'string') { locales = [locales]; } if (!locales.includes(this.config.defaultLocale)) { locales.push(this.config.defaultLocale); } this.config.locales = locales; i18n_1.default.configure({ locales, directory: path_1.default.join(this.config.rootDir, './i18n'), defaultLocale: this.config.defaultLocale, autoReload: false, updateFiles: !!this.args['auto-update-i18n-files'], }); } registerEvents() { if (typeof this.config.eventRegister === 'function') { this.eventEmitter.clearListeners(); this.config.eventRegister.call(this, this.eventEmitter); } } initRenderer() { this.dataSource = new FilesSource_1.default(this.config, this.postsDirPath); this.renderer = new TemplateRenderer_1.default(this.dataSource); } get outputRelativeDirectory() { const outDir = this.args['outdir']; if (outDir) { return outDir; } return this.config.devMode ? './dev' : './docs'; } get outputDirectory() { return path_1.default.resolve(this.config.rootDir, this.outputRelativeDirectory); } getOutputDirectory(locale) { const outdir = this.outputDirectory; if (this.isDefaultLocale(locale)) { return outdir; } return path_1.default.join(this.outputDirectory, locale); } get postsDirPath() { return path_1.default.join(this.config.rootDir, 'posts'); } logOutputDir() { gulplog_1.default.info('Output directory:', ansi_colors_1.default.blue(this.outputRelativeDirectory)); } async clean() { del_1.default.sync([this.outputDirectory]); } async cleanCache() { gulplog_1.default.info(ansi_colors_1.default.green('Cleaning cache')); del_1.default.sync(['./cache']); } async cleanPosts() { del_1.default.sync(`${this.postsDirPath}/*`); } loadData() { gulplog_1.default.info(ansi_colors_1.default.green('Loading posts')); this.initRenderer(); this.dataSource.loadData(); } _renderTemplates(templateGlob, renderFn, locale) { return new Promise((resolve) => { gulp_1.default.src(templateGlob, { allowEmpty: true }) .pipe(GulpUtils_1.default.handleStreamError()) .pipe(renderFn(locale)) .pipe(gulp_1.default.dest(this.getOutputDirectory(locale))) .on('end', resolve); }); } async renderTemplates(templateGlob, renderFn) { for (const locale of this.config.locales) { i18n_1.default.setLocale(locale); await this._renderTemplates(templateGlob, renderFn, locale); } } async generatePages() { gulplog_1.default.info(ansi_colors_1.default.green('Rendering pages')); await this.renderTemplates('./templates/pages/**/*.pug', this.renderer.renderPages.bind(this.renderer)); } async generatePosts() { gulplog_1.default.info(ansi_colors_1.default.green('Rendering posts')); await this.renderTemplates('./templates/posts/*.pug', this.renderer.renderPosts.bind(this.renderer)); } async generateTags() { gulplog_1.default.info(ansi_colors_1.default.green('Rendering tags')); await this.renderTemplates('./templates/tags/tag.pug', this.renderer.renderTags.bind(this.renderer)); } async generateTemplates() { await this.runSeries([ 'generatePages', 'generatePosts', 'generateTags', 'reloadBrowser', ]); } async generateRssFeed() { gulplog_1.default.info(ansi_colors_1.default.green('Generating RSS feed')); const rssGenerator = new RssGenerator_1.default(this.dataSource); for (const locale of this.config.locales) { i18n_1.default.setLocale(locale); rssGenerator.generate(this.getOutputDirectory(locale), locale); } } async generateCss() { gulplog_1.default.info(ansi_colors_1.default.green('Generating CSS')); return new Promise((resolve) => { let stream = gulp_1.default.src('./scss/main.scss', { allowEmpty: true, }); if (this.config.devMode) { stream = stream.pipe(gulp_sourcemaps_1.default.init()); } stream = stream.pipe(gulp_sass_1.default().on('error', gulp_sass_1.default.logError)); if (this.config.devMode) { stream = stream.pipe(gulp_sourcemaps_1.default.write()); } else { stream = stream.pipe(gulp_autoprefixer_1.default()).pipe(gulp_clean_css_1.default()); } return stream .pipe(gulp_1.default.dest(this.outputDirectory)) .on('end', resolve) .pipe(this.browserSync.stream()); }); } copyAssets() { gulplog_1.default.info(ansi_colors_1.default.green('Copying assets')); return new Promise((resolve) => { gulp_1.default.src('./assets/**/*', { allowEmpty: true }) .pipe(gulp_1.default.dest(this.outputDirectory)) .on('end', resolve); }); } reloadConfig() { gulplog_1.default.info(ansi_colors_1.default.green('Reloading config')); const configFilePath = this.args['configFilePath']; delete require.cache[configFilePath]; const newConfig = require(configFilePath); Object.assign(this.config, newConfig); this.registerEvents(); } reloadBrowser() { this.browserSync.reload(); } async onServe() { gulplog_1.default.info(ansi_colors_1.default.green('Starting local development server')); this.browserSync.init({ server: { baseDir: this.outputRelativeDirectory, }, port: this.args['port'] || DEV_PORT, open: this.args['no-open'] ? false : 'local', }); gulp_1.default.watch(this.args['configFilePath'], gulp_1.default.series('reloadConfig', 'dev', 'generateTemplates')); gulp_1.default.watch('./scss/**/*.@(scss|sass)', gulp_1.default.series('generateCss')); gulp_1.default.watch('./templates/pages/**/*.pug', gulp_1.default.series('generatePages', 'reloadBrowser')); gulp_1.default.watch('./templates/posts/**/*.pug', gulp_1.default.series('generatePosts', 'reloadBrowser')); gulp_1.default.watch('./templates/tags/**/*.pug', gulp_1.default.series('generateTags', 'reloadBrowser')); gulp_1.default.watch([ './templates/**/*.pug', '!./templates/pages/**/*.pug', '!./templates/posts/**/*.pug', '!./templates/tags/**/*.pug', ], gulp_1.default.series('generateTemplates', 'reloadBrowser')); gulp_1.default.watch('./assets/**/*', gulp_1.default.series('copyAssets', 'reloadBrowser')); const watcher = gulp_1.default.watch(this.postsDirPath + '/**/*.md'); watcher .on('change', this.onUpdateMarkdownPost.bind(this)) .on('add', this.onUpdateMarkdownPost.bind(this)); } onUpdateMarkdownPost(path) { if (!(this.dataSource instanceof FilesSource_1.default)) { gulplog_1.default.info('Not support compile posts from local files'); return; } const posts = this.dataSource.parsePostsFromPaths([path]); gulp_1.default.src('./templates/posts/*.pug', { allowEmpty: true }) .pipe(GulpUtils_1.default.handleStreamError()) .pipe(this.renderer.renderSpecifiedPosts(posts)) .pipe(gulp_1.default.dest(this.outputDirectory)) .pipe(this.browserSync.stream()); const postUrls = posts.map((p) => this.postRootUrl(p)); gulplog_1.default.info(`[POST UPDATED] ${postUrls.join(', ')}`); } async generateSamplePosts() { gulplog_1.default.info(ansi_colors_1.default.green('Generating sample posts')); const generator = new SampleGenerator_1.default(); const numberOfPosts = Number(this.args['number-of-posts']) || 10; generator.generateMarkdownPostsAndSave(numberOfPosts, this.postsDirPath); } async prod() { this.config.devMode = false; } async dev() { this.config.devMode = true; this.config.baseUrl = `http://localhost:${DEV_PORT}`; this.config.baseContext = ''; } async newDraft() { gulplog_1.default.info(ansi_colors_1.default.green('Generating a draft')); const generator = new SampleGenerator_1.default(); generator.generateEmptyMarkdownPostAndSave(this.postsDirPath); } runSeries(tasks) { return new Promise((resolve, reject) => { gulp_1.default.series(tasks)(function (err) { if (err) { reject(err); } else { resolve(); } }); }); } async build() { gulplog_1.default.info(ansi_colors_1.default.green('Start building')); this.logOutputDir(); await this.runSeries([ 'clean', 'copyAssets', 'loadData', 'generateTemplates', 'generateRssFeed', 'generateCss', ]); gulplog_1.default.info(ansi_colors_1.default.green("Build's completed")); } async serve() { await this.runSeries(['dev', 'build', 'onServe']); } wrap(func) { return async function () { const funcCapitalized = StringUtils_1.default.capitalize(func.name); gulplog_1.default.debug(`[BEFORE] ${funcCapitalized}`); await this.eventEmitter.emitSerial(`BEFORE:${funcCapitalized}`); await func.call(this); gulplog_1.default.debug(`[AFTER] ${funcCapitalized}`); await this.eventEmitter.emitSerial(`AFTER:${funcCapitalized}`); }; } registerTask(func) { gulp_1.default.task(func.name, this.wrap(func).bind(this)); } initTasks() { const tasks = [ this.prod, this.dev, this.clean, this.cleanPosts, this.cleanCache, this.copyAssets, this.loadData, this.generatePages, this.generatePosts, this.generateTags, this.generateTemplates, this.generateRssFeed, this.generateCss, this.generateSamplePosts, this.newDraft, this.onServe, this.reloadConfig, this.reloadBrowser, this.build, this.serve, ]; tasks.forEach((t) => this.registerTask(t)); } async run(tasks) { await this.runSeries(tasks); } } exports.default = SiteGenerator;