123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- /*
- * grunt-module-dependence
- * https://github.com/HanCong03/formula
- *
- * Copyright (c) 2014 hancong03
- * Licensed under the MIT license.
- */
- 'use strict';
- module.exports = function (grunt) {
- var PathModule = require("path"),
- UglifyJS = require("uglify-js");
- // 依赖池名称
- var depsPoolName = null,
- // 名称装饰后的映射表
- moduleMapping = {},
- idMapping = {},
- moudeIndex = 0;
- grunt.registerMultiTask('dependence', 'The best Grunt plugin ever.', function () {
- // 已处理后的module源码
- var transformedSource = null;
- var filenameList = [];
- var options = this.options({
- base: './',
- entrance: null,
- separator: '\n'
- }),
- moduleBase = PathModule.resolve(options.base) + PathModule.sep;
- initDepsPool();
- resetModuleIndex();
- this.files.forEach(function (fileConfig) {
- transformedSource = [];
- fileConfig.src.filter(function (filepath) {
- var source = null,
- currentModuleName = null;
- if (!grunt.file.exists(filepath)) {
- grunt.log.warn('Source file "' + filepath + '" not found.');
- return false;
- } else {
- source = '//' + filepath + '\n' + grunt.file.read(filepath);
- currentModuleName = getModuleName(filepath, source);
- if (currentModuleName.type === "id") {
- idMapping[currentModuleName.value] = moudeIndex;
- } else {
- moduleMapping[currentModuleName.value] = moudeIndex;
- }
- transformedSource.push(transform(moudeIndex, source));
- filenameList[moudeIndex] = currentModuleName.path;
- moudeIndex++;
- return true;
- }
- });
- for (var i = 0, len = transformedSource.length; i < len; i++) {
- transformedSource[i] = removeRequire(filenameList[i], transformedSource[i], moduleBase);
- }
- // 合并源码
- transformedSource = transformedSource.join( options.separator );
- transformedSource = wrap(transformedSource, options);
- transformedSource = format(transformedSource);
- grunt.file.write(fileConfig.dest, transformedSource);
- grunt.log.writeln('Concated ' + (moudeIndex).toString().cyan + ' Modules, File "' + fileConfig.dest + '" created.');
- });
- });
- /**
- * 根据给定的base目录和module路径以及源码获取格式化后的modulePath
- */
- function getModuleName(filepath, source) {
- filepath = PathModule.resolve(filepath);
- if (/\bdefine\s*\(\s*("|')([\s\S]+?)\1\s*,\s*/g.test(source)) {
- return {
- type: "id",
- value: RegExp.$2,
- path: filepath
- };
- }
- return {
- type: "path",
- value: PathModule.resolve(filepath),
- path: filepath
- };
- }
- /**
- * 初始化依赖池名称
- */
- function initDepsPool() {
- depsPoolName = '_p';
- }
- function resetModuleIndex() {
- moudeIndex = 0;
- }
- /**
- * 对module执行转换,更改其定义方式,使其可以脱离define方法
- * @param source
- */
- function transform(index, source) {
- var prefix = depsPoolName + "[" + index + "]",
- pattern = /(?:\/\*(?:[\s\S](?!\*\/))*?[\s\S]?\*\/\s*$)|(?:\/\/[^\n]*\s*$)/,
- lastIndex = -1,
- tailSource = null,
- tmpSource = null,
- match = null;
- source = source.replace(/\bdefine\s*\(\s*(?:("|')([\s\S]+?)\1\s*,\s*)?/g, prefix + "={\nvalue: ");
- tmpSource = source;
- while (pattern.test(tmpSource)) {
- tmpSource = tmpSource.replace(pattern, '');
- }
- lastIndex = tmpSource.lastIndexOf(')');
- tailSource = source.substring(lastIndex);
- source = source.substring(0, lastIndex);
- return source + tailSource.replace(/\)\s*;?/, '};');
- }
- /**
- * 删除require依赖
- */
- function removeRequire(filepath, source, moduleBase) {
- try {
- return source.replace(/\brequire\s*\(\s*("|')([\s\S]*?)\1\s*\)/g, function (match, sign, moduleName) {
- var originalName = moduleName;
- if (/^[.]{1,2}\//.test(moduleName)) {
- moduleName = PathModule.resolve(PathModule.dirname(filepath) + PathModule.sep + moduleName);
- } else if (idMapping.hasOwnProperty(moduleName)) {
- return depsPoolName + '.r(' + idMapping[moduleName] + ')';
- } else {
- moduleName = PathModule.resolve(moduleBase + moduleName);
- }
- if (PathModule.extname(moduleName) === "") {
- moduleName += ".js";
- }
- if (moduleMapping.hasOwnProperty(moduleName)) {
- return depsPoolName + ".r(" + moduleMapping[moduleName] + ")";
- }
- throw new ModuleNotfoundError(originalName);
- });
- } catch (e) {
- if (e.name === "ModuleNotfoundError") {
- grunt.fatal('Module [' + e.message + '] not found, in file: ' + filepath);
- }
- throw e;
- }
- }
- /**
- * 格式化源码
- * @param source
- */
- function format(source) {
- var ast = UglifyJS.parse(source);
- return ast.print_to_string({
- beautify: true,
- comments: 'all'
- });
- }
- /**
- * 包裹最终的源码
- * @param source
- */
- function wrap(source, options) {
- return getWrapTpl().replace(/^function\s*\(\s*\)\s*\{|\}\s*$/gi, '')
- .replace(/\$name/g, depsPoolName)
- .replace('$source;', source) + '\n' + getUseTpl(options.entrance);
- }
- /*-------------- 获取包裹函数模板*/
- function getWrapTpl() {
- return function () {
- var $name = {
- r: function (index) {
- if ($name[index].inited) {
- return $name[index].value;
- }
- if (typeof $name[index].value === 'function') {
- var module = {
- exports: {}
- },
- returnValue = $name[index].value(null, module.exports, module);
- $name[index].inited = true;
- $name[index].value = returnValue;
- if (returnValue !== undefined) {
- return returnValue;
- } else {
- for (var key in module.exports) {
- if (module.exports.hasOwnProperty(key)) {
- $name[index].inited = true;
- $name[index].value = module.exports;
- return module.exports;
- }
- }
- }
- } else {
- $name[index].inited = true;
- return $name[index].value;
- }
- }
- };
- $source;
- }.toString();
- }
- /**
- * Use函数入口
- * @param entrance
- */
- function getUseTpl(entrance) {
- var entranceMap = null,
- tmp = {},
- entranceName = entrance;
- if (entrance) {
- if (moduleMapping.hasOwnProperty(entrance)) {
- entrance = moduleMapping[entrance];
- } else if (idMapping.hasOwnProperty(entrance)) {
- entrance = idMapping[entrance];
- } else {
- entrance = null;
- }
- }
- if (!isNumber(entrance)) {
- entranceMap = 'var moduleMapping = ' + JSON.stringify(moduleMapping) + ';';
- } else {
- tmp[entranceName] = entrance;
- entranceMap = 'var moduleMapping = ' + JSON.stringify(tmp) + ';';
- }
- return entranceMap + '\nfunction use (name) {' + depsPoolName + '.r([moduleMapping[name]]);}';
- }
- function isNumber(val) {
- return typeof val === "number";
- }
- /*----------- 自定义错误类*/
- function ModuleNotfoundError(message) {
- this.message = message;
- this.name = 'ModuleNotfoundError';
- }
- ModuleNotfoundError.prototype = new Error();
- };
|