diff --git a/lib/cube/ext_api_process.js b/lib/cube/ext_api_process.js index 976d2a7..447d896 100644 --- a/lib/cube/ext_api_process.js +++ b/lib/cube/ext_api_process.js @@ -6,7 +6,8 @@ const babylon = require('babylon'); const babelType = require('babel-types'); const babelTraverse = require('babel-traverse').default; const babelGenerator = require('babel-generator').default; -const esminify = require('esminify'); +const uglifyJS = require("uglify-js"); +const uuid = require('uuid'); const debug = require('debug')('cube:wraper'); const utils = require('../utils'); @@ -33,12 +34,10 @@ function unique(arr) { /** * tryFiles 扫描文件 - * 根据给定的modPath, 识别出文件类型,默认是 script - * 如果要加载style和template, require的时候必须带后缀 - * - * 确定完类型之后,开始寻找存在的文件: - * 比如请求的文件是 index.js, 实际文件可以是 fname.$possibleExts - * $possibleExts 就是类型下所有注册的可能的后缀名称 + * 先用 tryFilesBaisc 扫描,假如没找到,再试下默认后缀的识别方法 + * + * eg. xxx.glsl => 找不到 + * xxx.glsl.js => 找到 * * @exceptions * @@ -46,7 +45,25 @@ function unique(arr) { * */ function tryFiles(cube, root, modPath) { - var origExt = path.extname(modPath); + try { + // 按原始后缀找一次 + return tryFilesBaisc(cube, root, modPath, path.extname(modPath)); + } catch (e) { + // 兜底用默认后缀找一次 + return tryFilesBaisc(cube, root, modPath, ''); + } +} + +/** + * tryFilesBaisc 扫描文件 + * 根据给定的modPath, 识别出文件类型,默认是 script + * 如果要加载style和template, require的时候必须带后缀 + * + * 确定完类型之后,开始寻找存在的文件: + * 比如请求的文件是 index.js, 实际文件可以是 fname.$possibleExts + * $possibleExts 就是类型下所有注册的可能的后缀名称 + */ +function tryFilesBaisc(cube, root, modPath, origExt) { var fName = path.basename(modPath, origExt); var dir = path.dirname(modPath); var arr; @@ -93,15 +110,18 @@ function tryFiles(cube, root, modPath) { } /** * testModPath and return the relative real path + * + * 要注意 browser module main 的关系:https://github.com/SunshowerC/blog/issues/8 + * * @param {Path} modPath abs root, may be file, may be module dir * @param {String} modName 在require中书写的模块名 + * @param {String} modRootPath 在require中书写的模块名的根节点,即 package.json 的所在位置 * @return {Path} relative path based on root */ -function testModPath(cube, modPath, modName) { +function testModPath(cube, modPath, modName, modRootPath) { let tmpModPath; let stat; let root = cube.config.root; - let moduleMap = cube.config.moduleMap; try { // test if dir try { @@ -109,89 +129,165 @@ function testModPath(cube, modPath, modName) { } catch(e) { // DO NOTHING } - try { - debug('testModPath: try single-file first.', modPath); - tmpModPath = tryFiles(cube, root, modPath); - } catch (e) { - if (stat && stat.isDirectory()) { - // get module default enter - try { - let pkg = require(path.join(modPath, './package.json')); - let alreadyFound = false; - /** - * first of all: moduleMap - */ - // tmpModPath = cube.config.moduleMap && cube.config.moduleMap[modName]; - // if (cube.config.moduleMap && tmpModPath) { - // tmpModPath = path.join(modPath, cube.config.moduleMap[modName]); - // debug('testModPath: try moduleMap[', modName, ',', cube.config.moduleMap[modName],']'); - // } - /** - * then search for browserify config in package.json - * "browserify": "d3.js" - */ - if (moduleMap && moduleMap[modName]) { - let tmp; - try { - tmp = fs.readlinkSync(modPath); - modPath = path.join(path.dirname(modPath), tmp); - } catch (e) { - // do nothing - } - tmpModPath = path.join(modPath, moduleMap[modName]); - } - else if (pkg.browserify && typeof pkg.browserify === 'string') { - tmpModPath = path.join(modPath, pkg.browserify); - debug('testModPath: try package.json.browserify', tmpModPath); - } - /** - * then search for browser config in package.json - * "browser": "browser.js" - */ - else if (pkg.browser && typeof pkg.browser === 'string') { - tmpModPath = path.join(modPath, pkg.browser); - debug('testModPath: try package.json.browser', tmpModPath); - } - /** - * then search for pkg.main - */ - else if (pkg.main && typeof pkg.main === 'string') { - tmpModPath = path.join(modPath, pkg.main); - debug('testModPath: try package.json.main ', tmpModPath); + // 文件夹和文件的处理趋于一致 + tmpModPath = testModPathBaisc(cube, modPath, modName, modRootPath, stat && stat.isDirectory()); + } catch (e) { + debug('testModPath: not found at last', modPath); + throw e; + } + return tmpModPath.substr(root.length); +} + +/** + * 文件处理: + * 找到包目录下 package.json,按 moduleMap => browserify => broswer => modPath => modPath/index.js + * + * 文件夹处理: + * 1. 找当前目录有没有 package.json,没有的话找包目录下 package.json + * 2. 按 moduleMap => browserify => broswer => main => modPath => modPath/index.js + */ +function testModPathBaisc(cube, modPath, modName, modRootPath, isDirectory) { + let root = cube.config.root; + let moduleMap = cube.config.moduleMap; + let tmpModPath; + // @ns/module module 都需要在路径上拼 node_modules + const rootPath = /^@?\w+/.test(modName) ? path.resolve(modRootPath, 'node_modules') : modRootPath; + try { + let pkg; + let isRoot = false; + // 获取 package.json + if (isDirectory) { + // 看看当前目录有没有 package.json, 优先级会更高 + isRoot = true; + try { + pkg = require(path.join(modPath, './package.json')); + } catch(e) {} // DO NOTHING + } + // 假如没有,不论文件夹还是文件都再次找一下包根目录有没有 package.json + if (!pkg) { + try { + isRoot = modPath === modRootPath; + pkg = require(path.join(modRootPath, './package.json')); + } catch (e) {} // DO NOTHING + } + + let alreadyFound = false; + if (moduleMap && moduleMap[modName]) { + let tmp; + try { + tmp = fs.readlinkSync(modPath); + modPath = path.join(path.dirname(modPath), tmp); + } catch (e) { + // do nothing + } + tmpModPath = path.join(modPath, moduleMap[modName]); + debug('testModPath: try moduleMap', tmpModPath); + } + + /** + * "browserify": "browserify.js" + */ + else if (pkg && pkg.browserify && typeof pkg.browserify === 'string') { + tmpModPath = path.join(modPath, pkg.browserify); + debug('testModPath: try package.json.browserify', tmpModPath); + } + + /** + * then search for browser config in package.json + * "browser": "browser.js" + */ + else if (pkg && pkg.browser && typeof pkg.browser === 'string') { + tmpModPath = path.join(modPath, pkg.browser); + debug('testModPath: try package.json.browser', tmpModPath); + } + + /** + * browser 为 obj 的 2 种情况, 先判断是否存在,然后获取 broswer path + * "browser": { + * "./aaa/aaa.js": "./aaa/dist/aaa.js", + * "fs": false + * } + */ + else if (pkg && pkg.browser && typeof pkg.browser === 'object' && !!exist(pkg.browser, modPath, rootPath)) { + const browserArr = Object.keys(browser); + for (let i =0; i < browserArr.length; i++) { + if (modPath === path.resolve(rootPath, browserArr[i])) { + if (browser[browserArr[i]]) { + // browser[key] 找到了,既拼接返回 + tmpModPath = path.resolve(rootPath, browser[browserArr[i]]) + } else { + // browser[key] 被置为了 false, 需要忽略,这边造一个伪文件 + const id = `./${uuid.v4()}.js`; + browser[browserArr[i]] = id; + // rootPath 文件夹可能不存在, 因为可能人为的拼了 node_modules try { - tmpModPath = tryFiles(cube, root, tmpModPath); - alreadyFound = true; - } catch (e) { - /** if package.main like : ./lib, it means ./lib/index.js **/ - tmpModPath = path.join(tmpModPath, './index.js'); - debug('testModPath: try package.json.main / index.js ', tmpModPath); + fs.statSync(rootPath); + } catch(e) { + fs.mkdirSync(rootPath); } - } else { - tmpModPath = path.join(modPath, './index.js'); - debug('testModPath: try module_dir/index.js', tmpModPath); - } - if (!alreadyFound) { - tmpModPath = tryFiles(cube, root, tmpModPath); - } - } catch (e) { - debug('testModPath: not found', e); - // can not find module main enter, use index.js as default - tmpModPath = path.join(modPath, 'index'); - debug('testModPath: try default module/index', tmpModPath); - try { - tmpModPath = tryFiles(cube, root, tmpModPath); - } catch (e) { - debug('testModPath: not found'); - throw e; + fs.writeFileSync(path.join(rootPath, id), 'module.exports = {};'); + tmpModPath = path.join(rootPath, id); } + break; } } + debug('testModPath: try package.json.browser object', tmpModPath); + } + /** + * then search for pkg.main + */ + else if (pkg && isRoot && pkg.main && typeof pkg.main === 'string') { + tmpModPath = path.join(modPath, pkg.main); + debug('testModPath: try package.json.main ', tmpModPath); + try { + tmpModPath = tryFiles(cube, root, tmpModPath); + alreadyFound = true; + } catch (e) { + /** if package.main like : ./lib, it means ./lib/index.js **/ + tmpModPath = path.join(tmpModPath, './index.js'); + debug('testModPath: try package.json.main / index.js ', tmpModPath); + } + } else { + try { + debug('testModPath: try modPath', modPath); + tmpModPath = tryFiles(cube, root, modPath); + alreadyFound = true; + } catch(e) { + tmpModPath = path.join(modPath, './index.js'); + debug('testModPath: try module_dir/index.js', tmpModPath); + } + } + + if (!alreadyFound) { + tmpModPath = tryFiles(cube, root, tmpModPath); + } + } catch(e) { + debug('testModPath: not found', e); + // can not find module main enter, use index.js as default + tmpModPath = path.join(modPath, 'index'); + debug('testModPath: try default module/index', tmpModPath); + try { + tmpModPath = tryFiles(cube, root, tmpModPath); + } catch (e) { + debug('testModPath: not found'); + throw e; } - } catch (e) { - debug('testModPath: not found at last', modPath); - throw e; } - return tmpModPath.substr(root.length); + return tmpModPath; +} + +// 判断 searchObj 中是否有 isTure +function exist(searchObj, modPath, rootPath) { + const searchArr = Object.keys(searchObj); + let isExist = false; + + for (let i =0; i < searchArr.length; i++) { + if (modPath === path.resolve(rootPath, searchArr[i])) { + isExist = true; + break; + } + } + return isExist; } function ifRootPath(path) { @@ -368,7 +464,8 @@ function fixAst(ast) { } function genCode(cube, qpath, ast, compress) { if (compress) { - let minifyOpt = cube.config.minify; + // 原有 minify 配置项直传 uglifyJS 会报错 + let minifyOpt = cube.config.uglifyMinify || {}; let opt = {}; if (typeof ast === 'string') { opt.code = ast; @@ -379,8 +476,17 @@ function genCode(cube, qpath, ast, compress) { */ opt.ast = fixAst(ast); } - opt.config = minifyOpt; - return esminify.minify(opt); + let out = babelGenerator(opt.ast, { + quotes: 'single', + comments: false, + compact: true, + minified: true, + concise: true, + filename: qpath, + }); + + out = uglifyJS.minify(out.code, minifyOpt); + return out.code; } else { if (typeof ast === 'string') { return ast; @@ -409,6 +515,7 @@ module.exports = { let dir = path.dirname(curModule); let count = 0; let nodeModulePath; + let moduleRootPath; let p; debug(`${curModule} resolve path: "${module}" in root: "${root}"`); /** @@ -428,9 +535,11 @@ module.exports = { }); } else if (/^@?\w+/.test(module)) { debug('module type: node_modules'); + var modName = module[0] === '@' ? module.split('/').slice(0, 2).join('/') : module.split('/')[0]; while (dir) { count++; nodeModulePath = path.join(root, dir, '/node_modules/', module); + moduleRootPath = path.join(root, dir); let ignore = this.checkIgnore(nodeModulePath.substr(root.length)); if (ignore.ignore) { this.log.warn(`"${module}" which required by "${curModule}" is ignored by .cubeignore config`); @@ -445,7 +554,7 @@ module.exports = { } } try { - p = testModPath(this, nodeModulePath, module); + p = testModPath(this, nodeModulePath, module, moduleRootPath); debug('resolvePath: ok > ', p); break; } catch (e) { @@ -469,12 +578,12 @@ module.exports = { if (/^\//.test(module)) { // if abs path: like "/jquery" debug('module type: abs_module', module); p = path.join(root, module); - } else { + } else { // if relative path : ./xxx debug('module type: relative_module', module); p = path.join(root, dir, module); } try { - p = testModPath(this, p, module); + p = testModPath(this, p, module, root); } catch (e) { debug('resolvePath error, module not found', module); this.log.warn(`required path:'${module}' not found in file: ${curModule}`); @@ -526,6 +635,8 @@ module.exports = { /** require 列表 */ data.requires = []; data.requiresOrigin = []; + /** queryPath 要重新计算 */ + data.queryPath = utils.moduleName(data.queryPath, data.type, config.release, config.remote); return callback(null, data); } diff --git a/lib/cube/index.js b/lib/cube/index.js index b4b3324..47c3aef 100644 --- a/lib/cube/index.js +++ b/lib/cube/index.js @@ -11,11 +11,11 @@ const EXT_API_PROCESS = require('./ext_api_process'); const EXT_API_TRANSFER = require('./ext_api_transfer'); const buildinProcessors = { - BUILDIN_JS: new require(path.join(__dirname, '../processor/js')), - BUILDIN_CSS: new require(path.join(__dirname, '../processor/css')), - BUILDIN_JSON: new require(path.join(__dirname, '../processor/json')), - BUILDIN_HTML: new require(path.join(__dirname, '../processor/html')), - BUILDIN_RAW: new require(path.join(__dirname, '../processor/raw')) + BUILDIN_JS: require(path.join(__dirname, '../processor/js')), + BUILDIN_CSS: require(path.join(__dirname, '../processor/css')), + BUILDIN_JSON: require(path.join(__dirname, '../processor/json')), + BUILDIN_HTML: require(path.join(__dirname, '../processor/html')), + BUILDIN_RAW: require(path.join(__dirname, '../processor/raw')) }; /** diff --git a/package.json b/package.json index 9416b6e..2b900a1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "fish (https://github.com/fishbar)", "name": "node-cube", "description": "a new way to write js in browser", - "version": "3.1.17-beta.2", + "version": "3.2.0", "homepage": "https://github.com/fishbar/cube", "repository": { "type": "git", @@ -30,27 +30,29 @@ "commander": "4.0.1", "connect": "^3.6.3", "debug": "4.1.0", - "esminify": "3.0.5", "lodash": "4.17.15", "serve-static": "1.12.4", + "uglify-js": "^3.14.1", + "uuid": "^8.3.0", "xfs": "~0.2.2" }, "devDependencies": { + "babel-preset-env": "*", + "cube-babel": "*", "cube-coffee": "*", "cube-ejs": "*", - "cube-babel": "*", "cube-jade": "*", + "cube-lazy-parse": "*", "cube-less": "*", "cube-react": "*", "cube-stylus": "*", - "cube-lazy-parse": "*", + "esminify": "3.0.5", "expect.js": "0.3.1", "jscoverage": "0.6.0", "jsdom": "6.2.0", "minami": "^1.1.1", "mocha": "3.2.0", - "supertest": "3.0.0", - "babel-preset-env": "*" + "supertest": "3.0.0" }, "optionalDependencies": {} } diff --git a/runtime/cube.js b/runtime/cube.js index b68c04c..e1c6030 100644 --- a/runtime/cube.js +++ b/runtime/cube.js @@ -22,12 +22,17 @@ var version; var strict = true; var debug = true; - var entrances = {}; // Cube.use's cb + var entrances = new Map(); // Cube.use's cb + // 兼容请求 key 带入参,返回 key 不带入参的情况。eg. 请求 /xxx?env=xx 返回 Cube('/xxx',), requireMap 缓存了 { '/xxx': '/xxx?env=xx' } + // 此兼容是在业务方已知的情况,后期会改造返回的代码头。 + var requireMap = {}; + var registerArr = []; var mockedProcess = { env: {NODE_ENV: 'production'} }; var mockedGlobal = undefined; + var esModule = false; var installedModules = {/*exports, fn, loaded, fired*/}; // The module cache var loading = {}; @@ -37,7 +42,7 @@ /* store requires before init */ var inited = false; var loadQueue = []; - console.time('cube load'); + debug && console.time('cube load'); /** * The require function * @param module @@ -89,11 +94,12 @@ */ function reBase(mod) { var offset = mod.indexOf ? mod.indexOf(remoteSeparator) : 0; - if (offset > 0) { - return remoteBase[mod.substr(0, offset)] + mod.substr(offset + 1); - } else { - return ''; - } + if (offset <= 0) return ''; + + var rbase = mod.substr(0, offset); + if (!remoteBase[rbase]) return ''; + + return remoteBase[rbase] + mod.substr(offset + 1); } function fixUseModPath(mods) { @@ -122,7 +128,7 @@ return false; } } - console.timeEnd('cube load'); + debug && console.timeEnd('cube load'); startAppAndCallback(); } @@ -141,9 +147,12 @@ } requires.forEach(function (require) { - if (installedModules[require]) { + if (installedModules[require] || getGlobalRegister(require)) { return; } + + // 只有拼 src 时要带上 m & ref 时才需要分离 require 里的入参 query, 平时 /xxx?query=xx 才作为 installedModules 的 key + const [mod, custom] = String(require).split('?'); // download form server var script = doc.createElement('script'); script.type = 'text/javascript'; @@ -155,8 +164,9 @@ }); }; - var rebaseName = reBase(require); - var srcPath = rebaseName || (base + require); + var rebaseName = reBase(mod); + var srcPath = rebaseName || (base + mod); + var q = []; if (version) { q.push(version); @@ -166,6 +176,13 @@ q.push('ref=' + referer); } + if (custom) { + const customArgs = parseQueryString(custom); + Array.prototype.push.apply(q, Object.keys(customArgs).map(c => { + return `${c}=${customArgs[c]}` + })); + } + if (q.length) { script.src = srcPath + '?' + q.join('&'); } else { @@ -177,23 +194,35 @@ loaded: false, fired: false }; + requireMap[mod] = require; loading[require] = true; }); checkAllDownloaded(); } + // require => datav:/npm/react/16.4.6?env=xxx + function getGlobalRegister(require) { + for (const register of registerArr) { + if (require && register.match.test(require)) { + return register.module; + } + } + return false; + } + /** * 运行模块 * @param module * @returns {*} */ function fireModule(module) { - var m = installedModules[module]; + var m = installedModules[module] || getGlobalRegister(module); if (!m) { + const err = new Error('Cube Error: Cannot find module ' + '\'' + module + '\''); if (strict) { - throw new Error('Cube Error: Cannot find module ' + '\'' + module + '\''); + throw err; } else { - log.error(e); + log.error(err); return {}; } } @@ -210,44 +239,46 @@ } } } - return m.exports; + return isEsModule(m.exports) ? m.exports.default : m.exports; } /** * 从Cube.use的文件开始自上而下运行,并调用回调函数 */ function startAppAndCallback() { - var key, arr; - console.time('cube exec'); - for (key in entrances) { - if (entrances.hasOwnProperty(key)) { - arr = key.split(','); - arr.forEach(function (entrance) { - var count = 0; - fireModule(entrance); - entrances[key].forEach(function (fn) { - var called = fn(installedModules[entrance].exports); - if (called) { - count++; - } - }); - if (entrances[key].length === count) { // 回调函数都执行完后删除 - delete entrances[key]; + debug && console.time('cube exec'); + for (let [key, value] of entrances) { + key.length && key.forEach(function (entrance) { + // 出现多次 startAppAndCallback, 在某次 startAppAndCallback 未结束时,entrances 增加了,但其实 loading 并未结束 + // 严格检查 + if (loading[entrance]) return; + var count = 0; + const exportModule = fireModule(entrance); + value.length && value.forEach(function (fn) { + var called = fn(exportModule); + if (called) { + count++; } }); - } + if (value.length === count) { // 回调函数都执行完后删除 + entrances.delete(key); + } + }); } - console.timeEnd('cube exec'); + debug && console.timeEnd('cube exec'); } - /** * 非构造函数,只供模块的wrapper调用 + * installedModules[name] name 是带入参的,不同入参的,不同key * @param name * @param requires * @param callback */ function Cube(name, requires, callback) { + // 暂时兼容返回的 name 不带入参的情况 + const oldName = String(name); + name = requireMap[name] || name; var mod = installedModules[name]; if (!mod) { mod = installedModules[name] = { @@ -257,6 +288,7 @@ } mod.loaded = true; mod.fn = callback; + requireMap[oldName] && delete requireMap[oldName]; if (loading[name]) { delete loading[name]; load(requires, name); @@ -304,6 +336,10 @@ if (config.global) { mockedGlobal = config.global; } + // support ES6 module, default is true + if (config.esModule !== undefined) { + esModule = config.esModule; + } inited = true; @@ -338,14 +374,16 @@ if (typeof mods === 'string') { mods = [mods]; } + if (!noFix) { mods = fixUseModPath(mods); } - if (!entrances[mods]) { - entrances[mods] = []; + // WARN: mods 是数组,会被自然的用 , 拼接,但 query 入参也可能带 , 所以这边 entrances 用 Map + if (!entrances.has(mods)) { + entrances.set(mods, []); } - entrances[mods].push(function () { + entrances.get(mods).push(function () { var apps = []; var length = mods.length; var firing = false; @@ -368,19 +406,31 @@ }; /** * register module in to cache - * @param {string} module [description] - * @param {} exports [description] + * @param {string} module [description] + * @param {} exports [description] + * @param {object} options 配置项 + * @param {string} options.matchType 匹配模式,version 默认为按版本全匹配; module 按库级别,只要库一致就替换 */ - Cube.register = function (module, exports) { + Cube.register = function (module, exports, { matchType = 'version' } = {}) { if (installedModules[module]) { - return log.error('Cube Error: Module ' + '\'' + module + '\'' + ' already registered'); + return log.warn('Cube Warning: Module ' + '\'' + module + '\'' + ' already registered'); } installedModules[module] = { exports: exports, fn: noop, loaded: true, - fired: true + fired: true, }; + + if (matchType === 'module') { + registerArr.push({ + require: module, + matchType, + match: new RegExp(`^datav:\/npm\/${module}\/([^\/]+)?$`), + module: installedModules[module], + }); + } + return this; }; /** @@ -477,4 +527,18 @@ Cube.use(cfg.main || 'index.js', function(app){app.run&& app.run();}); } } -})(window, null); + + function parseQueryString(param) { + let kvs = param.split('&'); + let obj = {}; + kvs.forEach((kv) => { + let tmp = kv.split('='); + obj[tmp[0]] = tmp[1]; + }); + return obj; + } + + function isEsModule(module) { + return esModule && module && typeof module === 'object' && module.__esModule; + } +})(window, null); \ No newline at end of file diff --git a/runtime/cube.min.js b/runtime/cube.min.js index 86771e8..ebf0315 100644 --- a/runtime/cube.min.js +++ b/runtime/cube.min.js @@ -1,4 +1,4 @@ /*! - * Cube v3.1.16 + * Cube v3.2.0 */ -(function(a,b){function c(){}function d(a,b){if(1===arguments.length)return k(a);var c=k(a);return m.css(c,b,a),a}function f(a){return function(b,c,d){2===arguments.length&&'function'===typeof c?(d=c,c=null,m.use(b,a,d)):m.use(b,a,function(a){a=m.css(a,c,b),d&&d(a)})}}function g(a){var b=a.indexOf?a.indexOf(t):0;return 0{m(a,[],()=>{console.error(`load module: ${a} failed.`)})};var d=g(a),f=d||r+a,h=[];n&&h.push(n),w&&(h.push('m'),h.push('ref='+b)),c.src=h.length?f+'?'+h.join('&'):f,C.appendChild(c),A[a]={exports:{},loaded:!1,fired:!1},B[a]=!0}}),i()):void E.push([a,b])}function k(b){var c=A[b];if(!c)if(v)throw new Error('Cube Error: Cannot find module \''+b+'\'');else return q.error(e),{};if(!c.fired)if(c.fired=!0,v)c.exports=c.fn.apply(a,[c,c.exports,d,f(b),y,z]);else try{c.exports=c.fn.apply(a,[c,c.exports,d,f(b),y,z])}catch(a){q.error(a),c.exports={}}return c.exports}function l(){var a,b;for(a in console.time('cube exec'),x)x.hasOwnProperty(a)&&(b=a.split(','),b.forEach(function(b){var c=0;k(b),x[a].forEach(function(a){var d=a(A[b].exports);d&&c++}),x[a].length===c&&delete x[a]}));console.timeEnd('cube exec')}function m(a,b,c){var d=A[a];d||(d=A[a]={exports:{},fired:!1}),d.loaded=!0,d.fn=c,B[a]?(delete B[a],j(b,a)):b.length&&j(b,a)}var n,o=window,p=document,q=console,r='',s={},t=':',u='utf-8',v=!0,w=!0,x={},y={env:{NODE_ENV:'production'}},z=void 0,A={},B={},C=p.querySelector('head'),D=!1,E=[];console.time('cube load'),m.setRemoteBase=function(a){Object.assign(s,a)},m.toString=function(){return'Cube:v3.1.16'},m.init=function(a){if(a.base&&'/'!==a.base&&(r=a.base.replace(/\/$/,'')),a.remoteBase)for(var b in a.remoteBase)a.remoteBase.hasOwnProperty(b)&&(s[b]=a.remoteBase[b].replace(/\/$/,''));for(a.charset&&(u=a.charset),a.version&&(n=a.version),void 0!==a.debug&&(w=a.debug),void 0!==a.strict&&(v=a.strict),a.env&&(y.env.NODE_ENV=a.env),a.global&&(z=a.global),D=!0;E.length;){var c=E.shift();j(c[0],c[1])}return this},m.use=function(b,d,f,g){if(!b)throw new Error('Cube.use(moduleName) moduleName is undefined!');return'function'===typeof d&&(g=f,f=d,d=void 0),d||(d='Cube.use'),f=f||c,'string'===typeof b&&(b=[b]),g||(b=h(b)),x[b]||(x[b]=[]),x[b].push(function(){var c=[],d=b.length,g=!1;return function(b){if(!g)return(c.push(b),c.length===d)?(g=!0,f.apply(a,c),!0):void 0}}()),j(b,d),this},m.register=function(a,b){return A[a]?q.error('Cube Error: Module \''+a+'\' already registered'):(A[a]={exports:b,fn:c,loaded:!0,fired:!0},this)};var F=/([^};]+)(\{[^}]+\})/g,G={};m.css=function(a,b,c){if(a){var d=c+'@'+b;if(!G[d]){G[d]=!0,b&&(a=a.replace(F,function(a,c,d){var f=c.split(',').map(function(a){return b+' '+a.trim()});return f.join(',')+d}));var f=p.createElement('style');return f.setAttribute('type','text/css'),f.setAttribute('mod',c),b&&f.setAttribute('ns',b),C.appendChild(f),f.innerHTML=a,a}}},m.debug=function(){o.localStorage&&o.addEventListener?(localStorage.cube='debug',location.reload()):q.error('Cube Error: Cannot debug, your browser does not support localStorage or addEventListener')},m.cache=function(){var a,b,c={},d={};for(a in A)A.hasOwnProperty(a)&&(b=A[a],b.loaded||(c[a]=b),b.fired||(d[a]=b));q.info('modules:',A),q.info('unloaded:',c),q.info('unfired:',d)},o.localStorage&&'debug'===localStorage.cube&&(w=!0,o.addEventListener('load',m.cache)),b=b||'Cube',a[b]?q.error('Cube Error: window.'+b+' already in using, replace the last "null" param in cube.js'):a[b]=m;var H=p.currentScript;if(H){var I=H.dataset;I.base&&(m.init(I),m.use(I.main||'index.js',function(a){a.run&&a.run()}))}})(window,null); \ No newline at end of file +(function(a,b){function c(){}function d(a,b){if(1===arguments.length)return k(a);var c=k(a);return m.css(c,b,a),a}function e(a){return function(b,c,d){2===arguments.length&&'function'===typeof c?(d=c,c=null,m.use(b,a,d)):m.use(b,a,function(a){a=m.css(a,c,b),d&&d(a)})}}function f(a){var b=a.indexOf?a.indexOf(v):0;if(0>=b)return'';var c=a.substr(0,b);return u[c]?u[c]+a.substr(b+1):''}function g(a){for(var b,c=a.length,d=0;d{m(a,[],()=>{console.error(`load module: ${a} failed.`)})};var d=f(h),e=d||t+h,g=[];if(p&&g.push(p),y&&(g.push('m'),g.push('ref='+b)),i){const a=n(i);Array.prototype.push.apply(g,Object.keys(a).map((b)=>`${b}=${a[b]}`))}c.src=g.length?e+'?'+g.join('&'):e,H.appendChild(c),F[a]={exports:{},loaded:!1,fired:!1},A[h]=a,G[a]=!0}}),h()):void J.push([a,b])}function j(a){for(const b of B)if(a&&b.match.test(a))return b.module;return!1}function k(b){var c=F[b]||j(b);if(!c){const a=new Error('Cube Error: Cannot find module \''+b+'\'');if(x)throw a;else return s.error(a),{}}if(!c.fired)if(c.fired=!0,x)c.exports=c.fn.apply(a,[c,c.exports,d,e(b),C,D]);else try{c.exports=c.fn.apply(a,[c,c.exports,d,e(b),C,D])}catch(a){s.error(a),c.exports={}}return o(c.exports)?c.exports.default:c.exports}function l(){y&&console.time('cube exec');for(let[a,b]of z)a.length&&a.forEach(function(c){if(G[c])return;var d=0;const e=k(c);b.length&&b.forEach(function(a){var b=a(e);b&&d++}),b.length===d&&z.delete(a)});y&&console.timeEnd('cube exec')}function m(a,b,c){const d=a+'';a=A[a]||a;var e=F[a];e||(e=F[a]={exports:{},fired:!1}),e.loaded=!0,e.fn=c,A[d]&&delete A[d],G[a]?(delete G[a],i(b,a)):b.length&&i(b,a)}function n(a){let b=a.split('&'),c={};return b.forEach((a)=>{let b=a.split('=');c[b[0]]=b[1]}),c}function o(a){return E&&a&&'object'===typeof a&&a.__esModule}var p,q=window,r=document,s=console,t='',u={},v=':',w='utf-8',x=!0,y=!0,z=new Map,A={},B=[],C={env:{NODE_ENV:'production'}},D=void 0,E=!1,F={},G={},H=r.querySelector('head'),I=!1,J=[];y&&console.time('cube load'),m.setRemoteBase=function(a){Object.assign(u,a)},m.toString=function(){return'Cube:v3.2.0'},m.init=function(a){if(a.base&&'/'!==a.base&&(t=a.base.replace(/\/$/,'')),a.remoteBase)for(var b in a.remoteBase)a.remoteBase.hasOwnProperty(b)&&(u[b]=a.remoteBase[b].replace(/\/$/,''));for(a.charset&&(w=a.charset),a.version&&(p=a.version),void 0!==a.debug&&(y=a.debug),void 0!==a.strict&&(x=a.strict),a.env&&(C.env.NODE_ENV=a.env),a.global&&(D=a.global),void 0!==a.esModule&&(E=a.esModule),I=!0;J.length;){var c=J.shift();i(c[0],c[1])}return this},m.use=function(b,d,e,f){if(!b)throw new Error('Cube.use(moduleName) moduleName is undefined!');return'function'===typeof d&&(f=e,e=d,d=void 0),d||(d='Cube.use'),e=e||c,'string'===typeof b&&(b=[b]),f||(b=g(b)),z.has(b)||z.set(b,[]),z.get(b).push(function(){var c=[],d=b.length,f=!1;return function(b){if(!f)return(c.push(b),c.length===d)?(f=!0,e.apply(a,c),!0):void 0}}()),i(b,d),this},m.register=function(a,b,{matchType:d='version'}={}){return F[a]?s.warn('Cube Warning: Module \''+a+'\' already registered'):(F[a]={exports:b,fn:c,loaded:!0,fired:!0},'module'===d&&B.push({require:a,matchType:d,match:new RegExp(`^datav:\/npm\/${a}\/([^\/]+)?$`),module:F[a]}),this)};var K=/([^};]+)(\{[^}]+\})/g,L={};m.css=function(a,b,c){if(a){var d=c+'@'+b;if(!L[d]){L[d]=!0,b&&(a=a.replace(K,function(a,c,d){var e=c.split(',').map(function(a){return b+' '+a.trim()});return e.join(',')+d}));var e=r.createElement('style');return e.setAttribute('type','text/css'),e.setAttribute('mod',c),b&&e.setAttribute('ns',b),H.appendChild(e),e.innerHTML=a,a}}},m.debug=function(){q.localStorage&&q.addEventListener?(localStorage.cube='debug',location.reload()):s.error('Cube Error: Cannot debug, your browser does not support localStorage or addEventListener')},m.cache=function(){var a,b,c={},d={};for(a in F)F.hasOwnProperty(a)&&(b=F[a],b.loaded||(c[a]=b),b.fired||(d[a]=b));s.info('modules:',F),s.info('unloaded:',c),s.info('unfired:',d)},q.localStorage&&'debug'===localStorage.cube&&(y=!0,q.addEventListener('load',m.cache)),b=b||'Cube',a[b]?s.error('Cube Error: window.'+b+' already in using, replace the last "null" param in cube.js'):a[b]=m;var M=r.currentScript;if(M){var N=M.dataset;N.base&&(m.init(N),m.use(N.main||'index.js',function(a){a.run&&a.run()}))}})(window,null); \ No newline at end of file diff --git a/test/index.js b/test/index.js index 88d7180..e76bf3e 100644 --- a/test/index.js +++ b/test/index.js @@ -250,7 +250,7 @@ describe('index.js', function () { request.get('/test/test_error.js?m') .expect(200) .expect(function (res) { - expect(res.text).match(/Unexpected token/ig); + expect(res.text).match(/Missing semicolon/ig); }) .end(done); });