Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inline processor #86

Open
wants to merge 6 commits into
base: 1.0/develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ var edp = require( 'edp-core' );

/**
* 遍历目录
*
*
* @inner
* @param {string|Array.<string>} dir 目录路径
* @param {ProcessContext} processContext 构建环境对象
Expand Down Expand Up @@ -78,7 +78,7 @@ function traverseDir( dir, processContext ) {

/**
* 向配置模块里注入构建处理器
*
*
* @inner
* @param {Object} conf 配置模块
*/
Expand All @@ -100,6 +100,7 @@ function injectProcessor( conf ) {
ReplaceDebug : require( './lib/processor/replace-debug' ),
TplMerge : require( './lib/processor/tpl-merge' ),
StringReplace : require( './lib/processor/string-replace' ),
InlineReplace : require( './lib/processor/inline-replace' ),
BcsUploader : require( './lib/processor/bcs-uploader' ),
OutputCleaner : require( './lib/processor/output-cleaner' )
} );
Expand All @@ -109,7 +110,7 @@ function injectProcessor( conf ) {

/**
* 处理构建入口
*
*
* @param {Object} conf 构建功能配置模块
* @param {Function=} callback 构建完成的回调函数
*/
Expand Down
180 changes: 180 additions & 0 deletions lib/processor/inline-replace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/**
* @file inline 处理器
* @author junmer[[email protected]]
*/

/* eslint-env node */

var edp = require('edp-core');
var AbstractProcessor = require('./abstract');

/**
* 获取文件内容
*
* @param {Object} processContext 构建环境对象
* @param {string} path 文件路径
* @return {string} 内容
*/
function getFileData(processContext, path) {

var fileInfo = processContext.getFileByPath(path);

if (fileInfo && fileInfo.data) {
return fileInfo.data;
}

var errMsg = 'inline file: ' + path + ' not found';

edp.log.fatal(errMsg);

throw new Error(errMsg);

}

/**
* 替换标签内容
*
* @param {string} content 目标全文
* @param {string} tag 标签
* @param {string} attribute 属性
* @param {Function} condition 替换条件
* @param {Function} tagReplacer 替换函数
* @return {string} 替换结果
*/
function replaceTag(content, tag, attribute, condition, tagReplacer) {

var attrReg = new RegExp('(' + attribute + ')=([\'"])([^\'"]+)\\2');
var tagReg = new RegExp('<' + tag + '([^>]+)>', 'g');

function replacer(match, attrStr) {
if (typeof condition === 'function' && !condition(match.slice(1))) {
return match;
}

/**
* 匹配的属性
*
* [match, attrName, start, value]
* @type {?Array}
*/
var attrMatch = attrStr.match(attrReg);

if (attrMatch && attrMatch[3]) {
return tagReplacer(attrMatch[3]);
}

return match;

}

return content.replace(tagReg, replacer);

}


/**
* isInlineTag
*
* @param {string} tagSource tag代码
* @return {boolean} 判断结果
*/
function isInlineTag(tagSource) {
return (/data-inline/).test(tagSource);
}

/**
* isStylesheet
*
* @param {string} tagSource tag代码
* @return {boolean} 判断结果
*/
function isStylesheet(tagSource) {
return (/rel=("|')stylesheet("|')/).test(tagSource);
}

/**
* inline 处理器
*
* @constructor
* @param {Object} options 初始化参数
*/
function InlineReplace(options) {

this.files = [
'*.html',
'*.htm',
'*.phtml',
'*.tpl',
'*.vm'
];

options = edp.util.mix({
condition: isInlineTag,
replacements: [
{
tag: 'link',
attribute: 'href',
condition: function (tagSource) {
return isInlineTag(tagSource) && isStylesheet(tagSource);
},
replacer: function (processContext) {
return function (path) {
return '<style>' + getFileData(processContext, path) + '</style>';
};
}
},
{
tag: 'script',
attribute: 'src',
condition: isInlineTag,
replacer: function (processContext) {
return function (path) {
return '<script>' + getFileData(processContext, path);
};
}
}
]
}, options);

AbstractProcessor.call(this, options);
}

InlineReplace.prototype = new AbstractProcessor();

/**
* 处理器名称
*
* @type {string}
*/
InlineReplace.prototype.name = 'InlineReplace';

/**
* 构建处理
*
* @param {FileInfo} file 文件信息对象
* @param {ProcessContext} processContext 构建环境对象
* @param {Function} callback 处理完成回调函数
*/
InlineReplace.prototype.process =
function (file, processContext, callback) {

var output = file.data;

this.replacements.forEach(function (item) {

output = replaceTag(
output,
item.tag,
item.attribute,
item.condition,
item.replacer(processContext)
);
});

file.setData(output);

callback();
};


module.exports = exports = InlineReplace;
18 changes: 18 additions & 0 deletions test/data/dummy-project/issue-70.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>

<link data-inline rel="stylesheet" href="./src/css/path-mapper.css">
<script data-inline src="./src/foo.js"></script>
<script data-inline src="./src/noooooooo.js"></script>

<script data-inline hehe="./src/foo.js"></script>
<script src="./src/bar.js"></script>

</head>
<body>
body
</body>
</html>
95 changes: 95 additions & 0 deletions test/inline-replace-processor.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/***************************************************************************
*
* Copyright (c) 2015 Baidu.com, Inc. All Rights Reserved
* $Id$
*
**************************************************************************/



/**
* inline-replace-processor.spec.js ~ 2015/01/04 15:22:11
* @author junmer([email protected])
* @version $Revision$
* @description 内联测试
**/
var path = require('path');

var base = require('./base');

var ProcessContext = require('../lib/process-context.js');
var InlineReplace = require('../lib/processor/inline-replace.js');

var Project = path.resolve(__dirname, 'data', 'dummy-project');
// var ConfigFile = path.resolve(Project, 'module.conf');

// var moduleEntries = 'html,htm,phtml,tpl,vm,js';
// var pageEntries = 'html,htm,phtml,tpl,vm';


describe('inline-replace-processor', function() {

var inline = new InlineReplace();
var processContext = new ProcessContext( {
baseDir: Project,
exclude: [],
outputDir: 'output',
fileEncodings: {}
});

var fileData = base.getFileInfo('data/dummy-project/issue-70.html', __dirname);

// js src/foo.js
var testJsFoo = base.getFileInfo('./src/foo.js', Project);
processContext.addFile(testJsFoo);

// css src/css/path-mapper.css
var testCss = base.getFileInfo('./src/css/path-mapper.css', Project);
processContext.addFile(testCss);

// js src/bar.js
var testJsBar = base.getFileInfo('./src/bar.js', Project);
processContext.addFile(testJsBar);

// 去掉空文件引用
var emptyScript = '<script data-inline src="./src/noooooooo.js"></script>';
fileData.data = fileData.data.replace(emptyScript, '');

inline.process(fileData, processContext, function() {

it('inline script', function() {
expect(fileData.data.indexOf(testJsFoo.data)).toBeGreaterThan(0);
});

it('inline link', function() {
expect(fileData.data.indexOf(testCss.data)).toBeGreaterThan(0);
});

it('only inline by data-inline', function() {
expect(fileData.data.indexOf(testJsBar.data)).toBe(-1);
});

});

// 测试空文件引用
var emptyFileData = base.getFileInfo('data/dummy-project/issue-70.html', __dirname);

try {

inline.process(emptyFileData, processContext, function() {

});

}
catch (ex) {

it('throw err when file not found', function() {
expect(ex).toBe(ex);
});
}

});



/* vim: set ts=4 sw=4 sts=4 tw=100: */