From a4e30e8f93387e21027db09f7fe5a4c37d6ab6d1 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Tue, 29 Apr 2014 20:59:57 -0400 Subject: [PATCH] Proof of concept: Load controller via ES6 module in Discourse --- .jshintrc | 3 +- Gemfile | 1 + Gemfile.lock | 3 + .../{history_controller.js => history.js.es6} | 2 +- .../javascripts/discourse/ember/resolver.js | 12 +++ app/assets/javascripts/vendor.js | 3 +- lib/discourse_iife.rb | 5 +- vendor/assets/javascripts/loader.js | 94 +++++++++++++++++++ 8 files changed, 119 insertions(+), 4 deletions(-) rename app/assets/javascripts/discourse/controllers/{history_controller.js => history.js.es6} (97%) create mode 100644 vendor/assets/javascripts/loader.js diff --git a/.jshintrc b/.jshintrc index 74450971d..ad107e4ee 100644 --- a/.jshintrc +++ b/.jshintrc @@ -72,5 +72,6 @@ "white": false, "eqnull": true, "quotmark": false, - "lastsemic": true + "lastsemic": true, + "esnext": true } diff --git a/Gemfile b/Gemfile index bd91d857c..2aa798e25 100644 --- a/Gemfile +++ b/Gemfile @@ -139,6 +139,7 @@ gem 'rest-client' gem 'rinku' gem 'sanitize' gem 'sass' +gem 'es6_module_transpiler-rails' gem 'sidekiq' gem 'sinatra', require: nil diff --git a/Gemfile.lock b/Gemfile.lock index 08d82bb18..29951eb96 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -84,6 +84,8 @@ GEM ember-source (1.6.0.beta.2) handlebars-source (~> 1.0) erubis (2.7.0) + es6_module_transpiler-rails (0.4.0) + execjs eventmachine (1.0.3) excon (0.28.0) execjs (2.0.2) @@ -404,6 +406,7 @@ DEPENDENCIES email_reply_parser-discourse ember-rails ember-source (= 1.6.0.beta.2) + es6_module_transpiler-rails eventmachine fabrication fakeweb (~> 1.3.0) diff --git a/app/assets/javascripts/discourse/controllers/history_controller.js b/app/assets/javascripts/discourse/controllers/history.js.es6 similarity index 97% rename from app/assets/javascripts/discourse/controllers/history_controller.js rename to app/assets/javascripts/discourse/controllers/history.js.es6 index e992ee2c3..9e458cde9 100644 --- a/app/assets/javascripts/discourse/controllers/history_controller.js +++ b/app/assets/javascripts/discourse/controllers/history.js.es6 @@ -7,7 +7,7 @@ @uses Discourse.ModalFunctionality @module Discourse **/ -Discourse.HistoryController = Discourse.ObjectController.extend(Discourse.ModalFunctionality, { +export default Discourse.ObjectController.extend(Discourse.ModalFunctionality, { loading: false, viewMode: "side_by_side", revisionsTextKey: "post.revisions.controls.comparing_previous_to_current_out_of_total", diff --git a/app/assets/javascripts/discourse/ember/resolver.js b/app/assets/javascripts/discourse/ember/resolver.js index f2f8dc848..a28574b29 100644 --- a/app/assets/javascripts/discourse/ember/resolver.js +++ b/app/assets/javascripts/discourse/ember/resolver.js @@ -1,3 +1,4 @@ +/* global requirejs, require */ /** A custom resolver to allow template names in the format we like. @@ -8,6 +9,17 @@ **/ Discourse.Resolver = Ember.DefaultResolver.extend({ + resolveController: function(parsedName) { + var moduleName = "discourse/controllers/" + parsedName.fullNameWithoutType, + module = requirejs.entries[moduleName]; + + if (module) { + module = require(moduleName, null, null, true /* force sync */); + if (module && module['default']) { module = module['default']; } + } + return module || this._super(parsedName); + }, + /** Attaches a view and wires up the container properly diff --git a/app/assets/javascripts/vendor.js b/app/assets/javascripts/vendor.js index 4a8d64d41..2b0eba8b0 100644 --- a/app/assets/javascripts/vendor.js +++ b/app/assets/javascripts/vendor.js @@ -5,9 +5,9 @@ //= require jquery_include.js //= require ember_include.js +//= require loader //= require message-bus //= require jquery.ui.widget.js -//= require_tree ./discourse/ember //= require LAB.js //= require Markdown.Converter.js //= require better_markdown.js @@ -38,3 +38,4 @@ //= require lock-on.js //= require ember-cloaking //= require break_string +//= require_tree ./discourse/ember diff --git a/lib/discourse_iife.rb b/lib/discourse_iife.rb index c6a1488d6..6fe24cfeb 100644 --- a/lib/discourse_iife.rb +++ b/lib/discourse_iife.rb @@ -12,6 +12,9 @@ class DiscourseIIFE < Sprockets::Processor return data if (path =~ /test\_helper\.js/) return data if (path =~ /javascripts\/helpers\//) + # Ignore ES6 files + return data if (path =~ /\.es6/) + # Ignore translations return data if (path =~ /\/translations/) @@ -23,4 +26,4 @@ class DiscourseIIFE < Sprockets::Processor "(function () {\n\nvar $ = window.jQuery;\n// IIFE Wrapped Content Begins:\n\n#{data}\n\n// IIFE Wrapped Content Ends\n\n })(this);" end -end \ No newline at end of file +end diff --git a/vendor/assets/javascripts/loader.js b/vendor/assets/javascripts/loader.js new file mode 100644 index 000000000..eaee097c7 --- /dev/null +++ b/vendor/assets/javascripts/loader.js @@ -0,0 +1,94 @@ +var define, requireModule, require, requirejs; + +(function() { + var registry = {}, seen = {}, state = {}; + var FAILED = false; + + define = function(name, deps, callback) { + registry[name] = { + deps: deps, + callback: callback + }; + }; + + function reify(deps, name, seen) { + var length = deps.length; + var reified = new Array(length); + var dep; + var exports; + + for (var i = 0, l = length; i < l; i++) { + dep = deps[i]; + if (dep === 'exports') { + exports = reified[i] = seen; + } else { + reified[i] = require(resolve(dep, name)); + } + } + + return { + deps: reified, + exports: exports + }; + } + + requirejs = require = requireModule = function(name) { + if (state[name] !== FAILED && + seen.hasOwnProperty(name)) { + return seen[name]; + } + + if (!registry[name]) { + throw new Error('Could not find module ' + name); + } + + var mod = registry[name]; + var reified; + var module; + var loaded = false; + + seen[name] = { }; // placeholder for run-time cycles + + try { + reified = reify(mod.deps, name, seen[name]); + module = mod.callback.apply(this, reified.deps); + loaded = true; + } finally { + if (!loaded) { + state[name] = FAILED; + } + } + + return reified.exports ? seen[name] : (seen[name] = module); + }; + + function resolve(child, name) { + if (child.charAt(0) !== '.') { return child; } + + var parts = child.split('/'); + var nameParts = name.split('/'); + var parentBase; + + if (nameParts.length === 1) { + parentBase = nameParts; + } else { + parentBase = nameParts.slice(0, -1); + } + + for (var i = 0, l = parts.length; i < l; i++) { + var part = parts[i]; + + if (part === '..') { parentBase.pop(); } + else if (part === '.') { continue; } + else { parentBase.push(part); } + } + + return parentBase.join('/'); + } + + requirejs.entries = requirejs._eak_seen = registry; + requirejs.clear = function(){ + requirejs.entries = requirejs._eak_seen = registry = {}; + seen = state = {}; + }; +})();