GithubHelp home page GithubHelp logo

zswang / jdists Goto Github PK

View Code? Open in Web Editor NEW
319.0 16.0 40.0 495 KB

A feature rich code block preprocessing tool.

License: MIT License

JavaScript 96.74% HTML 3.26%
code block processor javascript region jdists

jdists's Introduction

jdists 强大的代码块预处理工具

标签: jdists 教程


Build Status NPM version NPM download Coverage Status

jdists logo

背景

软件发布流程

code pretreatment

通常软件发布时会将源文件做一次「预处理」再编译成可执行文件,才发布到市场。

「预处理」的目的主要是出于以下几点

  • 配置线上运行环境,如调试服务地址需变更为实现线上地址;
  • 减少执行程序的大小,移除没有使用的代码或资源并压缩;
  • 增加逆向工程的成本,给代码做混淆(包括改变标识符和代码结构),降低可读性;
  • 移除或增加调试功能,关闭或开启一些特权后门。

一些 IDE 已在「编译」时集成了「预处理」功能。

什么是 jdists

jdists 是一款强大的代码块预处理工具。

什么是「代码块」(code block)?

通常就是注释或注释包裹的代码片段,用于表达各种各样的含义。

举个栗子

  • TODO 注释,表示代码中待完善的地方
/* TODO 功能待开发 */

  • wiredep 注释,表示引入 bower 组件依赖的 css 资源
	<!-- bower:css -->
	<link rel="stylesheet" href="bower_components/css/bootstrap.css" />
	<!-- endbower -->

  • jshint.js 顶部注释,表示版权声明
/*!
 * JSHint, by JSHint Community.
 *
 * This file (and this file only) is licensed under the same slightly modified
 * MIT license that JSLint is. It stops evil-doers everywhere:
 *
 *   Copyright (c) 2002 Douglas Crockford  (www.JSLint.com)
 * .........
 */

  • jshint.js 另一部分注释,表示代码检查配置项
/*jshint quotmark:double */
/*global console:true */
/*exported console */

总之,本文所指「代码块」就是有特殊意义的注释。

什么是「代码块预处理」?

指在代码编译之前,将代码文件按代码块粒度做一次编码或解析。

举个栗子,原本无效的代码片段,经过编码后变成了有效代码。

预处理前:

/*<jdists>
console.log('Hello World!');
</jdists>*/

预处理后:

console.log('Hello World!');

市面上还有哪一些「代码块预处理工具」?

市面上有不少,这里只列两个比较典型的。

  • 已被普遍使用的 JSDoc,功能是将代码中的注释抽离成 API 文档。
/**
 * Represents a book.
 * @constructor
 * @param {string} title - The title of the book.
 * @param {string} author - The author of the book.
 */
function Book(title, author) {
}

  • JSDev 是由 JSON 之父 Douglas Crockford 编写。jdists 与 JSDev 的功能类似,但 jdists 功能要复杂很多。

C command line example:

	 jsdev -comment "Devel Edition." <input >output test_expose enter:trace.enter exit:trace.exit unless:alert

JavaScript:

		output = JSDEV(input, [
				"test_expose",
				"enter:trace.enter",
				"exit:trace.exit",
				"unless:alert"
		] , ["Devel Edition."]);

input:

		// This is a sample file.

		function Constructor(number) {
				/*enter 'Constructor'*/
				/*unless(typeof number !== 'number') 'number', "Type error"*/
				function private_method() {
						/*enter 'private_method'*/
						/*exit 'private_method'*/
				}
				/*test_expose
						this.private_method = private_method;
				*/
				this.priv = function () {
						/*enter 'priv'*/
						private_method();
						/*exit 'priv'*/
				}
				/*exit "Constructor"*/
		}

output:

		// Devel Edition.
		// This is a sample file.

		function Constructor(number) {
				{trace.enter('Constructor');}
				if (typeof number !== 'number') {alert('number', "Type error");}
				function private_method() {
						{trace.enter('private_method');}
						{trace.exit('private_method');}
				}
				{
						this.private_method = private_method;
				}
				this.priv = function () {
						{trace.enter('priv');}
						private_method();
						{trace.exit('priv');}
				}
				{trace.exit("Constructor");}
		}

lightly minified:

		function Constructor(number) {
				function private_method() {
				}
				this.priv = function () {
						private_method();
				}
		}

预处理以「代码块」为粒度有什么优势?

  • 处理速度快,按需对代码块部分进行指定编码;
  • 控制力更强,可以控制每个字符的变化;
  • 不干扰编译器,编译器天然忽略注释。

现有「代码块预处理工具」存在什么问题?

  • 不容易学习和记忆。begin 还是 start,前缀还是后缀?
<!-- 乐居广告脚本 begin-->
/* jshint ignore:start */
/* TODO 待开发功能 */
  • 是否存在闭合不明显。什么时候生效,什么时候失效?
/*jshint unused:true, eqnull:true*/
/*test_expose
		this.private_method = private_method;
	*/
  • 没有标准,不能跨语言。JSDev 和 JSDoc 不能用于其他主流语言,如 Python、Lua 等。

代码预处理的思考

问题也就是:怎么定义、怎么处理、什么情况下触发。

怎么定义「代码块」?

本人拟订了一个基于「XML 标签」+「多行注释」的代码块规范: CBML

CBML

优势:

  • 学习成本低,XML、多行注释都是大家熟知的东西;
  • 标签是否闭合很明显;
  • 支持多种主流编程语言。

怎么处理「代码块」?

处理的步骤无外乎就是:输入、编码、输出

processor

经过解析 CBML 的语法树,获取 tagattribute 两个关键信息。

如果 tag 值为 <jdists> 就开始按 jdists 的规则进行处理。

整个处理过程由四个关键属性决定:

  1. import= 指定输入媒介
  2. export= 指定输出媒介
  3. encoding= 指定编码集合
  4. trigger= 指定触发条件

举个例子

/*<jdists export="template.js" trigger="@version < '1.0.0'">
	var template = /*<jdists encoding="base64,quoted" import="main.html?template" />*/
/*</jdists>

这里有两个代码块,还是一个嵌套结构

  • 外层代码块属性 export="template.js" 指定内容导出到文件 template.js(目录相对于当前代码块所在的文件)。
  • 外层代码块属性 trigger="@version < '1.0.0'" 指定命令行参数 version 小于 '1.0.0' 才触发。
  • 内层代码块属性 encoding="base64,quoted" 表示先给内容做一次 base64 编码再做一次 quoted 即,编码成字符串字面量。

什么情况下触发?

有两个触发条件:

  1. tag 值为 <jdists> 或者是被配置为 jdists 标签
  2. 当属性 trigger= 表达式判断为 true

jdists 基本概念

代码块 block

由 tag 标识的代码区域

代码块主要有如下三种形式:

  • 空内容代码块,没有包裹任何代码
/*<jdists import="main.js" />*/
  • 有效内容代码块,包裹的内容是编译器会解析
/*<jdists encoding="uglify">*/
	function format(template, json) {
		if (typeof template === 'function') { // 函数多行注释处理
			template = String(template).replace(
				/[^]*\/\*!?\s*|\s*\*\/[^]*/g, // 替换掉函数前后部分
				''
			);
		}
		return template.replace(/#\{(.*?)\}/g, function(all, key) {
				return json && (key in json) ? json[key] : "";
		});
	}
/*</jdists>*/
  • 无效内容代码块,包裹的内容也在注释中
/*<jdists>
console.log('version: %s', version);
<jdists>*/

标签 tag

  • <jdists> | 自定义

属性 attribute

  • import= 指定输入媒介
  • export= 指定输出媒介
  • encoding= 指定编码集合
  • trigger= 指定触发条件

媒介 medium

  • &content 默认为 "&"

  • file 文件 > 如: > main.js > index.html

  • #variant 变量 > 如: > #name > #data

  • [file]?block readonly 代码块,默认 file 为当前文件 > 如: > filename?tagName > filename?tagName[attrName=attrValue] > filename?tagName[attrName=attrValue][attrName2=attrValue2]

  • @argument readonly 控制台参数 > 如: > @output > @version

  • :environment readonly 环境变量 > 如: > :HOME > :USER

  • [...]{...} readonly 字面量 > 如: > [1, 2, 3, 4] > {title: 'jdists'}

  • 'string' readonly 字符串 > 如: > 'zswang'

触发器 trigger

触发器有两种表达式

  • 触发器名列表与控制台参数 --trigger 是否存在交集,存在则被触发

$ jdists ... --trigger release 触发

<!--remove trigger="release"-->
<label>release</label>
<!--/remove-->
  • 将变量、属性、环境变量表达式替换后的字面量结果是否为 true

$ jdists ... --version 0.0.9 触发

<!--remove trigger="@version < '1.0.0'"-->
<label>1.0.0+</label>
<!--/remove-->

如何扩展 jdists

可以参考项目中 processor 目录,中自带编码器的写法

举个栗子

var ejs = require('ejs');

/**
 * ejs 模板渲染
 *
 * @param {string} content 文本内容
 * @param {Object} attrs 属性
 * @param {string} attrs.data 数据项
 * @param {Object} scope 作用域
 * @param {Function} scope.execImport 导入数据
 * @param {Function} scope.compile 二次编译 jdists 文本
 */
module.exports = function processor(content, attrs, scope) {
	if (!content) {
		return content;
	}
	var render = ejs.compile(content);
	var data;
	if (attrs.data) {
		/*jslint evil: true */
		data = new Function(
			'return (' +
			scope.execImport(attrs.data) +
			');'
		)();
	}
	else {
		data = null;
	}
	return scope.compile(render(data));
};

详情参考:jdists Scope

用例

代码编译成 dataurl

通过块导入

<!--remove-->
<script>
/*<jdists encoding="base64" id="code">*/
console.log('hello world!');
/*</jdists>*/
</script>
<!--/remove-->

<!--jdists>
<script src="data:application/javascript;base64,/*<jdists import="?[id=code]" />*/"></script>
</jdists-->

通过变量导入

<!--remove-->
<script>
/*<jdists encoding="base64" export="#code">*/
console.log('hello world!');
/*</jdists>*/
</script>
<!--/remove-->

<!--jdists>
<script src="data:application/javascript;base64,/*<jdists import="#code" />*/"></script>
</jdists-->

实战

如何使用

jdists 依赖 node v0.10.0 以上的环境

安装

$ npm install jdists [-g]

命令行

Usage:

		jdists <input list> [options]

Options:

		-r, --remove                 Remove block tag name list (default "remove,test")
		-o, --output                 Output file (default STDOUT)
		-v, --version                Output jdists version
		-t, --trigger                Trigger name list (default "release")
		-c, --config                 Path to config file (default ".jdistsrc")

JS

var content = jdists.build(filename, {
		remove: 'remove,debug',
		trigger: 'release'
});

问题反馈和建议

https://github.com/zswang/jdists/issues

开发

复制项目代码

$ git clone https://github.com/zswang/jdists.git

初始化依赖

$ npm install

执行测试用例

$ npm test

预处理

$ npm run dist

代码覆盖率

$ npm run cover

关键文件目录结果

[lib]                 --- 发布后的代码目录
		jdists.js         --- jdists 业务代码
		scope.js          --- jdists 作用域
[processor]           --- 预制编码器
[processor-extend]    --- 未预制的编码器,可能会常用的
[src]                 --- 开发期代码
[test]                --- 测试目录
		[fixtures]        --- 测试用例
		test.js           --- 测试调度文件
index.js              --- jdists 声明
cli.js                --- jdists 控制台

jdists's People

Contributors

zswang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jdists's Issues

webpack 4.x

(node:5525) DeprecationWarning: loaderUtils.parseQuery() received a non-string value which can be problematic, see webpack/loader-utils#56
parseQuery() will be replaced with getOptions() in the next major version of loader-utils.
at Object.parseQuery (/Workspace/data-vision-fe/node_modules/jdists-loader/node_modules/loader-utils/index.js:78:3)
at Object.module.exports (/Workspace/data-vision-fe/node_modules/jdists-loader/lib/index.js:16:27)
at LOADER_EXECUTION (/Workspace/data-vision-fe/node_modules/loader-runner/lib/LoaderRunner.js:119:14)
at runSyncOrAsync (/Workspace/data-vision-fe/node_modules/loader-runner/lib/LoaderRunner.js:120:4)
at iterateNormalLoaders (/Workspace/data-vision-fe/node_modules/loader-runner/lib/LoaderRunner.js:229:2)
at Array. (/Workspace/data-vision-fe/node_modules/loader-runner/lib/LoaderRunner.js:202:4)
at Storage.finished (/Workspace/data-vision-fe/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:43:16)
at provider (/Workspace/data-vision-fe/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:79:9)
at /Workspace/data-vision-fe/node_modules/graceful-fs/graceful-fs.js:90:16
at FSReqWrap.readFileAfterClose [as oncomplete] (internal/fs/read_file_context.js:53:3)

v3.0 异步插件

异步插件

  • 异步处理
<!--jdists export="#translate"-->
function (content) {
  var request = require('request')
  return new Promise(function (resolve, reject) {
     request.post({
        url: 'https://xxx.com/translate',
        body: content,
     }, function (err, req, body) {
       if (err) {
          reject(err)
       } else {
         resolve(body)
       }
     })
  })
}
<!--/jdists-->

<!--jdists encoding="#translate"-->
Hello world!
<!--/jdists-->

v2.0.0

功能项

  • 浏览器版本
  • 移除不常用的插件

混淆真个js文件后,拿不到方法

我有一个问题,我希望把所有的要混淆加密的内容放在一个javascript文件里面,但是我在依照demo尝试的时候,发现对于一个方法函数,在使用 /*<jdists encoding="zero">*/ 混淆以后,在html文件中无法调用.

I have a problem, I want to put all the confusion to the encrypted content in a JavaScript file inside, but when I was in accordance with the demo to try, find a method to use the /*<jdists encoding= function, after the "zero" >*/ confused, unable to call in the HTML file

v3.0 批量导入

3.0 批量导入

  • 导入多个项
<!--jdists import="a.js,b.js" /-->
  • 模糊匹配
<!--jdists import="components/*.js" /-->

部分内容没有删除

源码

/*<debug>*/
        import Vue from 'vue';
        Vue.config.devtools = true;
/*</debug>*/

编译后

_vue2['default'].config.devtools = true

这行没有压缩掉,在fis3 的这个插件里面使用的

新功能筹备

处理 CommonJS 依赖模块

<!--replace encoding="require" base="../src" insert="_moduleId = '{{source}}';"-->
require("core/utils");
<!--/replace-->

常用打包工具的插件

  • grunt
  • fis
  • gulp

mac 下好像存在换行符的问题

大叔,Legend 用的是 1.3.1 版本,不小心升级到新版后 (按照 package.json 的写法,应该是 v1.3.8)之后,提示有换行符的兼容性问题。

package.json

"dependencies": {
     ...
    "jdists": "^1.0.12"
     ...
  },

部分错误信息如下:

> jdists page/index.html -o page/index.ejs -t ejs

>> env:
>> node\r: No such file or directory
>> 
>> npm
>> 
>> ERR!
>> Darwin 16.5.0
>> npm
>> ERR! argv
>> "/usr/local/bin/node" "/usr/local/bin/npm" "run" "_legend"
>> npm

推测可能是 Windows 下的换行符和 Mac 下的换行符不一致导致的,具体原因还有待进一步查明。

jdists 对js文件加密或者对有参数函数加密

您好 最近在研究您写的jdists 想使用jdists进行前端js进行混淆加密
demo大致都看了一下 一些基本的功能也可以进行加密了 可能由于对jdists理解还不是很深入 现在碰到一
个问题 没有看到合适的demo或者解决方法 想请教一下
问题是这样的 我看到jdists里都是对函数体内的代码进行加密,而一般js都是单独的文件,然后引入进来的
请问如何使用jdists对这个文件进行整体加密呢?
还是单独对这个js文件内的每个函数体内的代码进行加密吗?

我尝试直接在一个js文件中使用
/*<jdists encoding="aaencode">*/

var a = '1';

var b = 2;

/*</jdists>*/

在对函数体进行加密的时候无法获取到参数,第一种情况是undefined 第二种情况获得的

typeof arguments: object-----arguments: {"0":"_"}

function abc(params){
/*<jdists encoding="aaencode">*/
// 加密后 params is not defined
var a = params;
// or
var b = arguments[0];
.....
/*</jdists>*/
}

请教以上遇到的问题怎么解决呢 谢谢了

trigger没有触发的情况下,怎样才能移除标签?

代码中这么写,至于为什么这么写,是为了没有jdists处理的情况下,可以正常浏览

/*<product>*/
"debug": false
/*</product>*/
/*<jdists trigger="debug">
"debug": true
</jdists>*/

这么配置,是正常的,能删除product,并触发debug

remove: 'product,release',
trigger: 'debug,test'

可要是这么配置,咋一点反应都没有呢???不是应该把product标签、jdists整块移除?
现在是直接原原本本输出了

remove: 'debug,test',
trigger: 'product,release'

如果是我使用有问题,还望赐教~

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.