From 3d654fc18744845c76c4db17c8a755a24ab39076 Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 8 Mar 2018 13:57:37 +0400 Subject: [PATCH 1/3] add example of resolving config on client side --- plugins/c9.vfs.standalone/standalone.js | 32 +++-- plugins/c9.vfs.standalone/www/ide.html | 150 ++++++++++++------------ 2 files changed, 101 insertions(+), 81 deletions(-) diff --git a/plugins/c9.vfs.standalone/standalone.js b/plugins/c9.vfs.standalone/standalone.js index 5f68fa57..2f9dc859 100644 --- a/plugins/c9.vfs.standalone/standalone.js +++ b/plugins/c9.vfs.standalone/standalone.js @@ -94,6 +94,11 @@ function plugin(options, imports, register) { source: "query", optional: true }, + settings: { + type: "number", + source: "query", + optional: true + }, } }, function(req, res, next) { @@ -116,11 +121,18 @@ function plugin(options, imports, register) { }); opts.options.debug = req.params.debug !== undefined; + var workspaceSettings = getSettings(configName, options); + res.setHeader("Cache-Control", "no-cache, no-store"); + + if (req.params.settings == 1) + return res.json(workspaceSettings); + if (req.params.config == 1) - return res.json(getConfig(configName, opts)); + return res.json(getConfig(configName, workspaceSettings)); + res.render(__dirname + "/views/standalone.html.ejs", { - architectConfig: getConfig(configName, opts), + architectConfig: getConfig(configName, workspaceSettings), configName: configName, packed: opts.packed, standalone: true, @@ -326,9 +338,7 @@ function getConfigName(requested, options) { return name; } -function getConfig(configName, options) { - var filename = __dirname + "/../../configs/client-" + configName + ".js"; - +function getSettings(configName, options) { var installPath = options.settingDir || options.installPath || ""; var workspaceDir = options.options.workspaceDir; var settings = { @@ -347,6 +357,14 @@ function getConfig(configName, options) { settings[type] = data; } options.options.settings = settings; - - return require(filename)(options.options); + options.options.configName = configName; + options.options.manifest = { + version: options.options.manifest.version + }; + return options.options; +} + +function getConfig(configName, options) { + var filename = __dirname + "/../../configs/client-" + configName + ".js"; + return require(filename)(options); } diff --git a/plugins/c9.vfs.standalone/www/ide.html b/plugins/c9.vfs.standalone/www/ide.html index d5299556..dece83eb 100644 --- a/plugins/c9.vfs.standalone/www/ide.html +++ b/plugins/c9.vfs.standalone/www/ide.html @@ -23,6 +23,7 @@ From 9657bda937a8cc389082d8aa5f571d271f674da2 Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 8 Mar 2018 14:00:58 +0400 Subject: [PATCH 2/3] add commonjs support to architect-build --- .../architect-build/module-deps.js | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/plugins/node_modules/architect-build/module-deps.js b/plugins/node_modules/architect-build/module-deps.js index 4779c6b0..a11f5825 100644 --- a/plugins/node_modules/architect-build/module-deps.js +++ b/plugins/node_modules/architect-build/module-deps.js @@ -30,10 +30,7 @@ module.exports = function(mains, opts) { if (!opts.transforms) opts.transforms = []; - if (opts.node) - opts.transforms.push(wrapCJS); - - opts.transforms.push(removeLicenceComments, wrapUMD); + opts.transforms.push(removeLicenceComments, wrapCJS, wrapUMD); if (opts.pathConfig) { opts.paths = opts.paths || opts.pathConfig.paths; @@ -254,7 +251,9 @@ module.exports = function(mains, opts) { return output; }; - +function removeComments(src) { + return src.replace(/^\s*\/\/.+|^\s*\/\*[\s\S]*?\*\//gm, "") +} function normalizeModule(parentId, moduleName) { // normalize plugin requires if (moduleName.indexOf("!") !== -1) { @@ -274,7 +273,7 @@ function normalizeModule(parentId, moduleName) { return moduleName; } function getSubmodules(src, name) { - var m = src.replace(/^\s*\/\/.+|^\s*\/\*[\s\S]*?\*\//gm, "") + var m = removeComments(src) .match(/require\(\[([^\]]+)\]/gm); if (!m) return []; @@ -290,7 +289,7 @@ function getSubmodules(src, name) { return deps; } function getReqDeps(src, name) { - var m = src.replace(/^\s*\/\/.+|^\s*\/\*[\s\S]*?\*\//gm, "") + var m = removeComments(src) .match(/require\s*\(\s*(["'][^"'\n\r]+["'])\s*\)/gm); if (!m) return []; @@ -427,14 +426,8 @@ function wrapCJS(module) { return; module.source = module.source.replace(/^#.*\n/, ""); - var firstDefineCall = module.source.match(/define\(\s*[^)]*/); - if (firstDefineCall) { - // check if it is a normal define or some crazy umd trick - if (/define\(\s*function\s*\(/.test(firstDefineCall[0])) - return; - if (/define\(\s*\[[^\]]*\],\s*function\(/.test(firstDefineCall[0])) - return; - } + if (isCJS(module.source)) + return; console.log("wrapping module " + module.id); @@ -443,6 +436,21 @@ function wrapCJS(module) { + '});'; } +function isCJS(source) { + source = removeComments(source); + var firstDefineCall = source.match(/define\(\s*[^)]*/); + if (firstDefineCall) { + // check if it is a normal define or some crazy umd trick + if (/define\(\s*function\s*\(/.test(firstDefineCall[0])) + return; + if (/define\(\s*\[[^\]]*\],\s*\(?function\(/.test(firstDefineCall[0])) + return; + if (/typeof define/.test(source)) + return; + } + return true; +} + function debugSrc(module) { if (module.loaderModule) return; @@ -457,6 +465,7 @@ function quote(str) { } +module.exports.isCJS = isCJS; module.exports.getDeps = getDeps; module.exports.getSubmodules = getSubmodules; module.exports.resolveModulePath = resolveModulePath; From 1d886954531ee9e6a23ea178174e40aed5f88549 Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 8 Mar 2018 14:03:41 +0400 Subject: [PATCH 3/3] add support for commonjs and es6 --- plugins/c9.ide.ace/ace.js | 2 - plugins/c9.static/cdn.js | 14 +-- plugins/c9.vfs.standalone/www/test.html | 2 +- .../build_support/mini_require.js | 14 ++- .../architect-build/module-deps.js | 2 +- .../node_modules/architect-build/transform.js | 89 +++++++++++++++++++ 6 files changed, 109 insertions(+), 14 deletions(-) create mode 100644 plugins/node_modules/architect-build/transform.js diff --git a/plugins/c9.ide.ace/ace.js b/plugins/c9.ide.ace/ace.js index 3e2a1973..7cbab29a 100644 --- a/plugins/c9.ide.ace/ace.js +++ b/plugins/c9.ide.ace/ace.js @@ -1,5 +1,4 @@ /*global apf*/ -define(function(require, exports, module) { "use strict"; main.consumes = [ "Editor", "editors", "commands", "menus", "Menu", "MenuItem", "Divider", @@ -2930,4 +2929,3 @@ define(function(require, exports, module) { ace: handle }); } -}); diff --git a/plugins/c9.static/cdn.js b/plugins/c9.static/cdn.js index c7e942fe..a332217c 100644 --- a/plugins/c9.static/cdn.js +++ b/plugins/c9.static/cdn.js @@ -22,6 +22,7 @@ function main(options, imports, register) { var atomic = require("c9/atomic"); var error = require("http-error"); var frontdoor = require("frontdoor"); + var transform = require("architect-build/transform"); var cacheFiles = options.cacheFiles; @@ -32,6 +33,7 @@ function main(options, imports, register) { var resolveModulePath = require("architect-build/module-deps").resolveModulePath; connectStatic.getRequireJsConfig().useCache = options.useBrowserCache; + connectStatic.getRequireJsConfig().transform = "amd"; section.post("/__check__", [function(req, res, next) { req.params.hash = "any"; next(); @@ -152,6 +154,10 @@ function main(options, imports, register) { section.use(imports["connect.cors"].cors("*")); section.use(connect.getModule().compress()); + section.get("/~/:transform/:path*", [prepare, function(req, res, next) { + transform.sendFile(req, res, next); + }]); + section.get("/:hash/config/:name", [prepare, function(req, res, next) { var name = req.params.name.replace(/\.js$/, ""); var file = path.join(build.cacheDir, req.params.hash, "config", name + ".js"); @@ -198,7 +204,7 @@ function main(options, imports, register) { .on('error', onSendError(next)) .pipe(res); }]); - + register(); function sendCached(filename, req, res, next, loader) { @@ -259,11 +265,7 @@ function main(options, imports, register) { } function prepare(req, res, next) { - var hash = req.params.hash; - if (!hash.match(/^[a-z0-9]+$/)) - return next(new error.NotFound()); - - build.getPathConfig(hash, function(err, pathConfig) { + build.getPathConfig(req.params.hash, function(err, pathConfig) { if (err) return next(err); req.pathConfig = pathConfig; diff --git a/plugins/c9.vfs.standalone/www/test.html b/plugins/c9.vfs.standalone/www/test.html index bf167247..54905b9b 100644 --- a/plugins/c9.vfs.standalone/www/test.html +++ b/plugins/c9.vfs.standalone/www/test.html @@ -169,7 +169,7 @@ } }); - require.config({ useCache: true }); + require.config({ useCache: false, transform: "~es5/" }); mocha.bail(false); mocha.ignoreLeaks(true); mocha.fullTrace && mocha.fullTrace(); diff --git a/plugins/node_modules/architect-build/build_support/mini_require.js b/plugins/node_modules/architect-build/build_support/mini_require.js index d579bc94..34f51eac 100644 --- a/plugins/node_modules/architect-build/build_support/mini_require.js +++ b/plugins/node_modules/architect-build/build_support/mini_require.js @@ -286,11 +286,14 @@ var config = require.config = function(cfg) { config.paths[p] = cfg.paths[p]; }); - if (cfg.useCache && global.caches && location.protocol === "https:") { + if (cfg.useCache && global.caches && (location.protocol === "https:" || location.hostname == "localhost")) { config.useCache = true; checkCache(); } + if (cfg.transform) + config.transform = cfg.transform; + if (cfg.baseUrlLoadBalancers) config.baseUrlLoadBalancers = cfg.baseUrlLoadBalancers; }; @@ -374,11 +377,13 @@ require.toUrl = function(moduleName, ext, skipExt, skipBalancers) { var url = moduleName + ext; if (!absRe.test(url)) { - url = (config.baseUrl || require.MODULE_LOAD_URL + "/") + url; + if (ext == ".js" && require.config.transform) + url = ("~/" + require.config.transform + "/" + url).replace("//", "/"); + url = (config.baseUrl || require.MODULE_LOAD_URL + "/") + url; } if (url[0] === "/" && config.baseUrlLoadBalancers && !skipBalancers && !config.useCache) { var n = Math.abs(hashCode(url)) % config.baseUrlLoadBalancers.length; - url = config.baseUrlLoadBalancers[n] + url; + url = config.baseUrlLoadBalancers[n] + url; } return url; }; @@ -415,7 +420,7 @@ var loadScriptWithTag = function(path, id, callback) { }; s.onerror = function(e) { processLoadQueue({ - message: "Error loading script " + id + ":" + path, + message: "Error loading script " + id + ":" + path, id: id, path: path }); @@ -437,6 +442,7 @@ function loadText(path, cb) { } /*** cache ***/ +/*global Response, Request*/ var host = location.protocol + "//" + location.hostname + (location.port ? ":" + location.port : ""); var loadScript = function(path, id, callback) { if (!config.useCache) diff --git a/plugins/node_modules/architect-build/module-deps.js b/plugins/node_modules/architect-build/module-deps.js index a11f5825..e5a6c68e 100644 --- a/plugins/node_modules/architect-build/module-deps.js +++ b/plugins/node_modules/architect-build/module-deps.js @@ -426,7 +426,7 @@ function wrapCJS(module) { return; module.source = module.source.replace(/^#.*\n/, ""); - if (isCJS(module.source)) + if (!isCJS(module.source)) return; console.log("wrapping module " + module.id); diff --git a/plugins/node_modules/architect-build/transform.js b/plugins/node_modules/architect-build/transform.js new file mode 100644 index 00000000..069f3e7c --- /dev/null +++ b/plugins/node_modules/architect-build/transform.js @@ -0,0 +1,89 @@ +var moduleDeps = require("./module-deps"); +var fs = require("fs"); +var send = require("send"); + +exports.transform = function(code, options) { + if (/^"disable compress"/.test(code)) + return code; + + if (options.mode == "babel") { + var babel = require("babel"); + return babel.transform(code, { + "presets": [ + ["env", { + "targets": { + "browsers": ["last 2 versions", "ie >= 11"] + } + }] + ] + }).code; + } + else if (options.mode == "ts") { + var ts = require("typescript"); + return ts.transpileModule(code, { + compilerOptions: { + downlevelIteration: true, + suppressExcessPropertyErrors: true, + removeComments: true, + module: ts.ModuleKind.CommonJS + } + }).outputText; + } + else if (options.mode == "buble") { + return require("buble").transform(code).code; + } + else { + if (moduleDeps.isCJS(code)) { + code = "define(function(require, exports, module) {" + code + "\n})"; + } + return code; + } +}; + + +var cache = Object.create(null); +exports.sendFile = function(req, res, next) { + var path = req.params.path; + var filePath = moduleDeps.resolveModulePath(path, req.pathConfig.pathMap); + + if (!/\.js$/.test(filePath) || /(browserified|\.min|test\d)\.js$/.test(filePath)) { + return send(req, filePath.substr(req.pathConfig.root.length)) + .root(req.pathConfig.root) + .on('error', next) + .pipe(res); + } + + fs.stat(filePath, function(err, stat) { + if (err) return next(err); + var mtime = stat.mtime.valueOf(); + var etag = 'W/"' + stat.size.toString(16) + "-" + mtime.toString(16) + '"'; + + var noneMatch = req.headers && req.headers['if-none-match']; + + if (noneMatch && noneMatch == etag) { + res.statusCode = 304; + res.end(); + return; + } + + if (cache[path] && cache[path].etag == etag) + return res.end(cache[path].value); + res.setHeader("ETag", etag); + cache[path] = null; + fs.readFile(filePath, "utf8", function(err, value) { + if (err) + return next(err); + var t = Date.now(); + try { + value = exports.transform(value, { path: filePath }); + } catch (e) { + return next(e); + } + var delta = Date.now() - t; + res.setHeader('Server-Timing', 'transform=' + delta); + cache[path] = { value: value, etag: etag }; + res.end(value); + }); + }); +}; +