最近本着新年新气象的想法,想换套新的博客园皮肤。javascript
以前本身作了一套制做皮肤的解决方案,这是当时分享皮肤以及解决方案的博客:分享一款博客园皮肤及其解决方案。css
不过在制做新的皮肤过程当中,使用这个解决方案时仍是遇到了不少问题。html
而为了更方便地制做新皮肤,就升级了原先的解决方案,搭建了这套博客园皮肤制做脚手架。前端
项目地址已从github换到了码云:https://gitee.com/vvjiang/cnblogs-skin。java
具体的使用方式项目文档有介绍,这里就不赘述了,接下来主要是讲脚手架解决了什么问题以及解决方法。node
原先的解决方案其实很简单,将css写在不一样的less文件中,而后用webpack-dev-server保证本地开发。webpack
在须要build最终的css时,经过mini-css-extract-plugin提取样式到最终的css文件中。git
自定义js部分,就是一个单独的文件,在开发环境下经过引用这个文件来处理,构建时不须要这个文件,直接复制粘贴到博客园后台便可。github
如今说一说原有方案遇到的一些问题:web
而个人脚手架就是针对这些问题来给出具体的解决方案。
其实css压缩并非个问题,主要是以前考虑到你们能够在博客里面按F12看css文件,而后方便copy功能。
可是如今咱们仍是须要去作一下css压缩的工做。
采用的是webpack4的常规方案:optimize-css-assets-webpack-plugin。
具体的能够百度,或者直接查看个人项目代码,不展开说这个。
js压缩的问题不能靠webpack,由于靠webpack打包应用生成的最终js是包括一些webpack代码的,不那么纯粹。
而若是以库文件的方式打包,那么可能还须要配置两个webpack配置文件来处理,有点麻烦。
因此我采用的方案是不借助webpack,而是本身用nodejs引入uglify-js这个库来打包。
这里只写一下js压缩的关键代码:
const UglifyJS = require("uglify-js"); function buildMoudle(moduleName) { fs.readFile(`./src/js/${moduleName}.js`, (err, data) => { const code = data.toString() let jsCode = '' // 若是相应的模块js代码不为空,那么就进行压缩处理 if (code !== '') { jsCode = UglifyJS.minify(code).code } // ... }) }
这里实际上使用nodejs读取指定模块文件,而后使用uglify-js压缩和混淆js代码,最后再用nodejs将代码写入到指定模块文件便可。
其实到了这一步很好解决,我们经过nodejs读取指定模板html文件的文本,将其中的占位符替换为压缩后的js代码便可。
先看看咱们的模板文件:
<div id="loadingProcess"></div> <script type="text/javascript" src="https://magi.com/assets/thirdparty/leader-line.min.js"></script> <script type="text/javascript"> {{jsContent}} </script>
再看看咱们转换的关键代码:
/** * 用指定模块的Html代码包裹js代码 * @param {*} jsCode js代码 * @param {*} moduleTemplateHtml html模板代码 */ function wrapJSCodeByHtml(jsCode, moduleTemplateHtml) { return moduleTemplateHtml.replace("{{jsContent}}", jsCode) }
最后将返回的最终代码输出到指定模块的html文件便可。
可是上面这一步还有点问题,我们的模块文件改变了,还要去手动改变我们开发环境的模板文件,要否则开发环境和最终生成的不一样啊。
可是手动作这个事情太蠢了,多作几回彻底就打消了我继续作皮肤的欲望了。
因此这里咱们须要经过一个自定义的webpack插件,将这部分html代码和js注入到开发环境的html中:
/** * 自制注入页首和页脚html模块代码的webpack插件 */ function InjectBlogHtmlPlugin() { console.info('html模块注入') } InjectBlogHtmlPlugin.prototype.apply = function (compiler) { compiler.hooks.compilation.tap('InjectBlogHtmlPlugin', (compilation) => { compilation.hooks.htmlWebpackPluginBeforeHtmlProcessing.tapAsync( 'InjectBlogHtmlPlugin', function (data, callback) { const headerJsText = fs.readFileSync(`./src/js/header.js`).toString() const headerHtmlText = fs.readFileSync(`./src/template/header.html`).toString() const footerJsText = fs.readFileSync(`./src/js/footer.js`).toString() const footerHtmlText = fs.readFileSync(`./src/template/footer.html`).toString() data.html = data.html.replace('{{headerHtml}}', headerHtmlText.replace("{{jsContent}}", headerJsText)) data.html = data.html.replace('{{footerHtml}}', footerHtmlText.replace("{{jsContent}}", footerJsText)) callback(null, data) } ) }) };
htmlWebpackPluginBeforeHtmlProcessing是编译时的一个hook,在html处理以前。
这里会将未压缩的代码和模板html一块儿注入到生成的html中。
到了这一步,这个生成页首和页尾模板文件的功能已经差很少了。
然而你会发如今开发环境下改变页首模板文件,页面并不会热更新。
这是由于页首html模板文件与入口文件不存在依赖关系,因此不能热更新。
这里你可能会有疑问,明明html-webpack-plugin依赖的页面模板文件就没有问题,修改以后能够热更。
那是由于html-webpack-plugin依赖的模板内部是作了处理的,因此改html-webpack-plugin的页面模板文件能够热更新。
可是咱们这里的页首模板文件和页尾模板文件确定不能这么处理,那么咱们让他们存在依赖便可。
在入口文件app.js中引入相应的模板文件。
import './src/template/header.html' import './src/template/footer.html'
可是很显然这样会引发编译报错,因此咱们须要修改webpack配置用raw-loader进行处理一下。
module: { rules: [ //... { test: /\.(htm|html)$/, use: [ 'raw-loader' ] } ], },
这样一来修改页首模板和页尾模板就能够实现热更新了。
关于这个问题须要分两点去解决,第一点是img元素的图片加载问题,另一点是css中background-image中图片的加载问题。
首先咱们须要明白是什么缘由致使的,这两个点都是由于同一个缘由:防盗链处理。
当咱们加载博客园的图片资源时,请求头部会有个Referrer Policy的头域,默认值为no-referrer-when-downgrade。
它会向服务器发送咱们当前引用这个资源的页面的地址,而博客园服务器会对不是博客园的地址作过滤处理,咱们的图片也就加载不出来。
第一点很好解决,在咱们的categoryList.html、index.html和read.html三个页面模板文件的头部加上下面这段代码便可:
<meta name="referrer" content="no-referrer"/>
这样一来,咱们图片的请求,不会再向图片服务器传递 Referrer值。
第二点很差解决,由于图片是在css中的,上面的方式对它无效。
最开始的想法是有没有办法拦截图片请求而后作处理,然而并无什么太好的办法。
后来我又想着本地开启一个代理,用nodejs的express去处理图片资源,可是太过麻烦。
最后的处理方式比较质朴:
将css图片中引用的图片下载下来放在本地,开发的时候加载本地图片,生成的时候经过webpack的publicPath生成博客园的地址。
其实这种玩法是借鉴了我平常操做中的场景:开发的时候加载本地图片,发布的时候将本地图片上传到cdn以后,引用cdn地址。
而如今博客园的图片资源就是做为这个cdn地址存在的。
这里提及来简单,其实改造起来仍是作了很多事的。
首先要将css中引用的图片下载下来,存放在src文件夹下的imgs文件夹中。
而后修改全部css中的博客园图片地址为本地图片地址。
由于以前都是用的网络图片地址,如今用本地图片的话,那么就要用file-loader处理一下。
须要在webpack.config.js中配置publicPath,可是考虑到我们的webpack配置在生产和开发时都会用到,因此须要区分开发和生产环境。
这里没有用两套配置,由于毕竟改动不大,因此直接使用cross-env添加NODE_ENV环境变量,而后在webpack.config.js中加以判断。
这个方案其实不太满意,由于有一个手动下载图片,并修改开发代码的步骤。
不过也还能接受吧,毕竟只有第一次可能工做量大一点,您若是有更好的方法但愿能够提一下建议。
仍然有一点不足之处,可是这个不足之处仅仅只针对除我以外的使用者。
由于我本身的皮肤力求简洁,因此不少博客功能我没有用到,也就没有在页面模板中加入这方面的html代码。
若是您有须要的话,能够下载脚手架后,修改template文件夹中的三个html模板便可:
我本身用的是博客园的blank皮肤模板,若是您用的是博客园其余的皮肤模板的话,可能也须要进行相应修改。
最后吐槽一下,当我改造旧项目时,发现有些引用自博客园的css路径变更致使引用css失效。
并且有一次我发现本身博客里面的样式有些奇怪,缘由是博客园的html结构中id仍是class来的变更了一个名字。
这些会致使我须要去更新一下受到影响的页面模板,略显烦躁。
不过总的来讲,问题不大,仍是最喜欢博客园,主要是能够定制皮肤以及玩出各类新高度,如今还能锻炼下本身搭建前端脚手架的能力。
诸位要是对这个脚手架有什么好的建议,也但愿不吝赐教。