通过gulp-inject,gulp-inline-source
公司需要开发一个页面弹窗 项目文件也不多,但是由于受到开发思想的限制,导致目录结构太过标准。
# 这是我的目录结构
Root
| num-limit.html
| trialoverdue-ntask.html
| trialoverdue.html
+---assets
+---css
| |-- sty.css
| |-- sty.css.map
| |-- sty.less
+---img
| |-- gou2.png
| |-- ic.png
| |-- pic.png
| |-- pie.htc
| |-- xing.png
+---js
|-- jq.js
|-- numlimit.js
|-- tran.js
|-- tran2.js
然而项目交付的时候的目录结构与开发结构并不一致,这就难受了呀
# 这是最终目录结构
Root
| num-limit.html
| trialoverdue-ntask.html
| trialoverdue.html
+---img
|-- gou2.png
|-- ic.png
|-- pic.png
|-- pie.htc
|-- xing.png
解决思路
其实这个问题,自己手动复制替换就完全能解决问题。直到接触到 gulp 发现其可以减少很多重复工作,这过程中查找太多资料,也陆续试用了多个方案。大概的步骤如下:
- 将图片等资源文件放到与 html 文件同级的 img 目录下
- 将页面中用到的 css,js 文件整合到 html 中,而不是通过引入的方式加载。
- 压缩代码
上面步骤中,移动和压缩资源通过 gulp 对应的模块很好实现,关键点是在于如何替换 html 中引入的 css 和 js 文件 ,下面的方案也是针对这步进行记录。
方案一 gulp-inject
【注意点】需要在插入替换 js 的代码地方使用注释语句做好标记
在 html 文件中标记好需要插入代码的区块,其主要原理就是通过读取注释区块中的对应字段来判断是否进行插入替换
html 的文件修改如下,可见在开发环境中这个 inject 代码标记块并不会影响页面,因为是注释语法。代码执行后,会将注释代码包裹区域里面的内容替换成我们规定的内容。
<!-- inject:FileContent:css -->
<link rel="stylesheet" href="assets/css/sty.css" />
<!-- endinject -->
....
<!-- inject:FileContent:js -->
<script src="assets/js/jq.js"></script>
<script src="assets/js/tran2.js"></script>
<!-- endinject -->
gulpfile.js
const inject = require("gulp-inject");
...
function inJect() {
return src("./src/*.html")
.pipe(replace("./assets/", "")) //替换html文件里面的资源路径位置,需要依赖gulp-replace
.pipe(
inject(src(["./dist/css/*.css", "./dist/js/*.js"]), {
starttag: "<!-- inject:FileContent:{{ext}} -->", // '<!-- -->'这是关键,判断插入位置
endtag: "<!-- endinject -->",
relative: true,
transform: function (filePath, file) {
if (filePath.slice(-3) === ".js") {
return (
"<script>" +
file.contents.toString("utf8") +
"</script>"
);
}
if (filePath.slice(-4) === ".css") {
return (
"<style>" +
file.contents.toString("utf8") +
"</style>"
);
}
// 将文件内容作为字符串返回
return file.contents.toString("utf8");
},
})
)
.pipe(dest("./dist/"));
}
以上方案通过判断 inject:FileContent 对应的值,来进行判断到底是插入 css,还是 js,比较暴力。
【问题】因为读取的是 assets/目录下的所有 js 和 css 文件,所以插入的 js 和 css 也是所有的文件,然而有些 js 代码和 css 样式是根本不需要的。
【优化】通过仔细阅读 gulp-inject 文档,发现可以设置相应的标记参数来实现插入对应需要的 js 和 css
html 文件标记如下
<!-- inject:../dist/js/jq.min.js -->
<script src="assets/js/jq.js"></script>
<!-- endinject -->
<!-- inject:../dist/js/tran2.min.js -->
<script src="assets/js/tran2.js"></script>
<!-- endinject -->
gulpfile.js
const inject = require("gulp-inject");
...
function inJect() {
return src("./src/*.html")
.pipe(
inject(src("./dist/js/*.js"), {
starttag: "<!-- inject:{{path}} -->", // 通过获取标记中的path变量,来动态的进行对应代码的插入替换
relative: true,
transform: function (filePath, file) {
// return file contents as string
return (
"<script>" +
file.contents.toString("utf8") +
"</script>"
);
},
})
)
.pipe(
inject(src("./dist/css/*.css"), {
// 插入css文件,通过指定starttag的方式,直接擦入替换
starttag: "<!-- inject:head:css -->",
transform: function (filePath, file) {
// return file contents as string
return (
"<style>" + file.contents.toString("utf8") + "</style>"
);
},
})
)
.pipe(dest("./dist/"));
}
【问题】还是存在问题,就是 html 文件中需要有不同的代码标记块,而且代码标记块中需要指定插入的 js 路径,-- inject:../dist/js/tran2.min.js --
,如果页面中引入 js 过多则对应标记太多。
【优化】把共用的 js 用一个标记包裹,不同的 js 单独包裹,从而减少标记数量。
方案二gulp-inline-source
【注意点】 跟 gulp-inject 一样,需要在 html 代码中添加对应的标记,不过 gulp-inline-source 的标记不是注释区块,而是属性名称。代码如下
在对应的 html 文件中声明属性:inline
(属性默认是 inline,可以通过参数 attribute 的值进行自己配置)
<link rel="stylesheet" href="assets/css/sty.css" inline />
.....
<script src="assets/js/jq.js" inline></script>
<script src="assets/js/tran.js" inline></script>
gulpfile.js
const inlineSource = require("gulp-inline-source");
...
function inJect() {
return src("./src/*.html")
.pipe(replace("./assets/", "")) //替换html文件中的资源目录
.pipe(inline(
//将html文件中对应的有inline属性的<script>,<link>,替换成对应的代码块。默认会将原始代码进行压缩
{
compress: false, // 代码不压缩,默认为true
pretty: true // 代码首行空格美化,对齐工整.当compress为false的时候起作用(默认为false)
}
))
.pipe(dest("./dist/"));
}
最后
方案二对比方案一,在 html 中需要进行的标记操作较少。但是其替换的 css 和 js 是开发时候的原文件,并没有进行额外的处理。我在使用方案二的时候,如果开启默认的压缩,现代浏览器不会出现问题,但是老版本的 ie8 就出现了 js 报错的问题。所以只能暂时不开启压缩。而使用方案一就不会出现兼容性问题,因为我在插入 js 之前就已经对原 js 文件通过gulp-uglify
进行了处理,通过相关配置,就能完美兼容到 ie8.
其他相关配置
gulp 输出到同一目录
.pipe(dest(function (file) { return file.base; }))
mincss 配置
const cssmin = require('gulp-minify-css');
.pipe(cssmin({
advanced: false, //类型:Boolean 默认:true [是否开启高级优化(合并选择器等)]
compatibility: 'ie7', //保留ie7及以下兼容写法 类型:String 默认:''or'*' [启用兼容模式; 'ie7':IE7兼容模式,'ie8':IE8兼容模式,'*':IE9+兼容模式]
keepBreaks: true //类型:Boolean 默认:false [是否保留换行]
}))
minjs 配置
const uglify = require('gulp-uglify');
.pipe(
uglify({
ie8: true,//兼容到ie8
compress:
{
drop_console: true, // 过滤 console
drop_debugger: true // 过滤 debugger
}
})
)
gulp 中的 jquery gulp-cheerio
const cheerio = require("gulp-cheerio");
.pipe(
cheerio(function ($) {
$("script").each(function () {
console.log($(this).attr('src'));
});
}))