头部背景图片
senrenbankaの部落格 |
senrenbankaの部落格 |

制作一个不轻量的hexo主题:cube

前言

之前自己用Laravel写了个博客, 用了一段时间果断弃之, 又用回了原来的Hexo, 上网找了下主题, 没找到自己想要的, 于是决定自己写一款主题(在写主题的过程倒是找到了很多自己觉得不错的2333), 这篇文章只是用来记录一下最近这段时间写这个主题的过程, 中间存在着很多的问题, 主题目前还没有正式完成, 最近实习 + 毕设搞得比较颓, 9月份之后会逐步完善修复。

hexo-theme-cube
cube-generator
示例网站

其中cube-generator是主题的生成器, 通过运行对应的gulp命令能够重新生成主题cube

构建主题

看了一些github上的主题项目, 很多都是ES5 + jQuery的实现方式, 于是自己有了一个想法,用ES6来写这个主题样式, 最终代码是要转化为ES5的, 那么就需要babel进行转换了, 又因为写样式决定采用SaSS, 所以就决定用gulp进行自动化构建, 所以最终的决定是:

  • gulp中利用browserify + babelify对前端代码进行ES6到ES5的转换, Babel转换的规则写在babelify上面, js代码的入口规定为source/js/app.js, app.jsimport对应功能的js代码, gulp进行bundle script的生成代码如下:
const b = browserify({
    cache: {},
       packageCache: {},
       entries: path.join('./source/js/app.js'),
       debug: true
})

// 配置babel转换规则
b.transform(babelify, {
       presets: ['env', 'es2015', 'stage-2'],
       plugins: [['transform-runtime', {
           'polyfill': true,
           'regenerator': true
       }]]
})

gulp.task('buildScript', bundle)

// b.on('update', bundle)

// bundle生成script.js并且放在cube/source/js/script.js上面
function bundle() {
       return b.bundle()
           .on('error', err => console.log(err))
           .pipe(source('script.js'))
           .pipe(buffer())
           .pipe(sourcemaps.init({ loadMaps: true }))
           .pipe(uglify())
           .pipe(sourcemaps.write('./'))
           .pipe(gulp.dest(path.join(Path.theme, Path.source, '/js')))
}

JS的部分如下所示:

JS模块

  • 在gulp中利用gulp-inject, 将source/sass/目录下除了style.scss.scss文件用@import的方式进行注入,最后再对style.scssgulp-sass进行编译生成最终的css文件, 代码如下:
// highlight和lightgallery已经在其他文件通过@import的方式引用了索引文件
// 所以这里不注入对应文件夹里面的文件
function buildStyle() {
       const injectFiles = gulp.src([
           path.join(Path.source, 'sass/*.scss'),
           '!' + path.join(Path.source, 'sass/highlight/*.scss'),
           '!' + path.join(Path.source, 'sass/lightgallery/*.scss'),
           '!' + path.join(Path.source, '/sass/style.scss')
       ], { read: false })
        const injectOptions = {
           transform(filePath) {
               filePath = filePath.replace(`${Path.source}/sass/`, '');
               filePath = filePath.replace('_', '');
               return `@import "${filePath}";`
        },
           starttag: '// injector',
           endtag: '// endinjector',
           addRootSlash: false
    }

    return gulp.src(path.join(Path.source, '/sass/style.scss'))
           .pipe(Inject(injectFiles, injectOptions))
           .pipe(Sass())
           .pipe(postcss([ autoprefixer() ]))
           .pipe(cleanCss({debug: true}))
           .pipe(gulp.dest(path.join(Path.theme, Path.source, '/css')))
}
  • 将上面两部生成的script.jsstyle.css注入到header.ejslayout.ejs(注入的其实是ejs的模板写法), 然后将ejs文件,字体和图片等静态资源移动到主题文件夹中,将主题文件夹放置到Hexo站点的themes文件夹里面, 完成主题的生成:
gulp.task('injectStyle', ['buildStyle'], () => {
     const injectStyle = gulp.src(path.join(Path.theme, Path.source,'/css/style.css'), {
          read: false
     })

     const injectOptions = {
         starttag: '<!-- inject:style -->',
         addRootSlash: false,
         transform(filePath) {
             return `<link href="<%- url_for('css/${filePath}') %>" rel="stylesheet" type="text/css">`
         },
         ignorePath: path.join(Path.theme, Path.source, 'css')
     }

     return gulp.src(path.join(Path.layout, '/_partial/head.ejs'))
         .pipe(Inject(injectStyle, injectOptions))
         .pipe(gulp.dest(path.join(Path.theme, Path.layout, '_partial')))
})


gulp.task('injectScript', ['buildScript'], () => {
    const injectScript = gulp.src(path.join(Path.theme, Path.source, '/js/script.js'), {
        read: false
    })

    const injectOptions = {
        starttag: '<!-- inject:script -->',
        addRootSlash: false,
        transform(filePath) {
            return `<script src="<%- url_for('js/${filePath}') %>"></script>`
        },
        ignorePath: path.join(Path.theme, Path.source, 'js')
    }

    return gulp.src(path.join(Path.layout, '/layout.ejs'))
        .pipe(Inject(injectScript, injectOptions))
        .pipe(gulp.dest(path.join(Path.theme, Path.layout)))
})

gulp.task('inject', ['injectStyle', 'injectScript'], () => {
    return gulp.src([
        '!' + path.join(Path.layout, '/layout.ejs'),
        '!' + path.join(Path.layout, '/_partial/head.ejs'),
        path.join(Path.layout, '/**/*.ejs')
    ]).pipe(gulp.dest(path.join(Path.theme, Path.layout)))
})

通过这两个任务产生的ejs代码如下:

    layout.ejs:

    <!-- inject:script -->
    <script src="<%- url_for('js/script.js') %>"></script>
    <!-- endinject -->

    _partial/head.ejs:

    <!-- inject:style -->
    <link href="<%- url_for('css/style.css') %>" rel="stylesheet" type="text/css">
    <!-- endinject -->
  • 通过gulp-watch监听对应领域的文件, 如果发生了变动就重新生成主题

通过上面四个步骤的构建, 就可以在source/js/里面编写es6代码了, 开启gulp watch之后会监听对应模板和scss以及js等文件的变化重新生成主题(用node 子进程进行了hexo clean & hexo g, 只要等待终端提示即可直接hexo s查看效果

博客的构建

Hexo博客的构建没什么特别的, 可以参考github上一些优秀的Hexo主题项目的布局格式, 结合Hexo官方文档, 在对应的模板ejs引用对应的Hexo变量实现主题模板的编写即可。关于这个主题的具体构建代码可以看cube-generator

待解决问题

  • gulp的构建写得还是很乱, 原本的想法是想用browser-sync实现修改文件实时刷新的, 但是hexo启动服务器采用的是hexo s启动, 要先通过hexo g重新生成public文件夹才会刷新内容, 所以用browser-sync的想法也不了了之,后续有时间要把gulp的构建重新写一遍

  • 移动端方面做的调试不多, 貌似在一些手机浏览器会出现一些奇怪的问题(我的小米4自带的原生浏览器加载不了用lightgallery读取的图片, 我觉得这个不是我的锅233, 但是有时间还是要看看),highlight.js加载较慢导致手机打开博客页面一开始可以横向滚动(应该是我用了async进行异步的关系)

  • 第三方评论系统只测试了畅言和gitment, disqus因为我这边暂时无法那个(你懂的), 所以这个部分还没写, 很多评论系统都挂了,所以在想是不是要自己也来写个评论系统2333

  • 其他一些奇奇怪怪的问题….

avatar AONOSORA 今生今世轮回尽, 来世愿为幻想乡