Index: extensions/renderer/module_system.cc |
diff --git a/extensions/renderer/module_system.cc b/extensions/renderer/module_system.cc |
index 4a685e34caaa25dfa358c56727c4511a64632b63..d91d40fffa5046e9ee0b220037fa18a34552d8b3 100644 |
--- a/extensions/renderer/module_system.cc |
+++ b/extensions/renderer/module_system.cc |
@@ -16,6 +16,7 @@ |
#include "extensions/renderer/console.h" |
#include "extensions/renderer/safe_builtins.h" |
#include "extensions/renderer/script_context.h" |
+#include "gin/modules/module_registry.h" |
#include "third_party/WebKit/public/web/WebFrame.h" |
#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h" |
@@ -121,13 +122,17 @@ ModuleSystem::ModuleSystem(ScriptContext* context, SourceMap* source_map) |
context_(context), |
source_map_(source_map), |
natives_enabled_(0), |
- exception_handler_(new DefaultExceptionHandler(context)) { |
+ exception_handler_(new DefaultExceptionHandler(context)), |
+ weak_factory_(this) { |
RouteFunction( |
"require", |
base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this))); |
RouteFunction( |
"requireNative", |
base::Bind(&ModuleSystem::RequireNative, base::Unretained(this))); |
+ RouteFunction( |
+ "requireAsync", |
+ base::Bind(&ModuleSystem::RequireAsync, base::Unretained(this))); |
RouteFunction("privates", |
base::Bind(&ModuleSystem::Private, base::Unretained(this))); |
@@ -137,6 +142,8 @@ ModuleSystem::ModuleSystem(ScriptContext* context, SourceMap* source_map) |
v8::Object::New(isolate)); |
global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModuleSystem), |
v8::External::New(isolate, this)); |
+ |
+ gin::ModuleRegistry::From(context->v8_context())->AddObserver(this); |
} |
ModuleSystem::~ModuleSystem() { Invalidate(); } |
@@ -243,6 +250,8 @@ v8::Local<v8::Value> ModuleSystem::RequireForJsInner( |
GetIsolate(), "require", v8::String::kInternalizedString)), |
natives->Get(v8::String::NewFromUtf8( |
GetIsolate(), "requireNative", v8::String::kInternalizedString)), |
+ natives->Get(v8::String::NewFromUtf8( |
+ GetIsolate(), "requireAsync", v8::String::kInternalizedString)), |
exports, |
// Libraries that we magically expose to every module. |
console::AsV8Object(), |
@@ -254,7 +263,8 @@ v8::Local<v8::Value> ModuleSystem::RequireForJsInner( |
context_->safe_builtins()->GetJSON(), |
context_->safe_builtins()->GetObjekt(), |
context_->safe_builtins()->GetRegExp(), |
- context_->safe_builtins()->GetString(), }; |
+ context_->safe_builtins()->GetString(), |
not at google - send to devlin
2014/07/01 18:13:05
btw this was git cl format being a pain, which is
Sam McNally
2014/07/02 03:26:35
I think clang format prefers this formatting now.
|
+ }; |
{ |
v8::TryCatch try_catch; |
try_catch.SetCaptureMessage(true); |
@@ -558,12 +568,33 @@ v8::Handle<v8::Value> ModuleSystem::RequireNativeFromString( |
return i->second->NewInstance(); |
} |
+void ModuleSystem::RequireAsync( |
+ const v8::FunctionCallbackInfo<v8::Value>& args) { |
+ CHECK_EQ(1, args.Length()); |
+ std::string module_name = *v8::String::Utf8Value(args[0]->ToString()); |
+ v8::Handle<v8::Promise::Resolver> resolver( |
+ v8::Promise::Resolver::New(GetIsolate())); |
+ v8::Handle<v8::Promise> promise(resolver->GetPromise()); |
+ scoped_ptr<v8::UniquePersistent<v8::Promise::Resolver> > persistent_resolver( |
+ new v8::UniquePersistent<v8::Promise::Resolver>(GetIsolate(), resolver)); |
+ gin::ModuleRegistry* module_registry = |
+ gin::ModuleRegistry::From(context_->v8_context()); |
+ module_registry->LoadModule(GetIsolate(), |
+ module_name, |
+ base::Bind(&ModuleSystem::OnModuleLoaded, |
+ weak_factory_.GetWeakPtr(), |
+ base::Passed(&persistent_resolver))); |
+ args.GetReturnValue().Set(promise); |
+ if (module_registry->available_modules().count(module_name) == 0) |
+ LoadAmdModule(module_name); |
+} |
+ |
v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) { |
v8::EscapableHandleScope handle_scope(GetIsolate()); |
// Keep in order with the arguments in RequireForJsInner. |
v8::Handle<v8::String> left = v8::String::NewFromUtf8( |
GetIsolate(), |
- "(function(require, requireNative, exports, " |
+ "(function(require, requireNative, requireAsync, exports, " |
"console, privates," |
"$Array, $Function, $JSON, $Object, $RegExp, $String) {" |
"'use strict';"); |
@@ -572,6 +603,17 @@ v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) { |
v8::String::Concat(left, v8::String::Concat(source, right)))); |
} |
+v8::Handle<v8::String> ModuleSystem::WrapAmdSource( |
+ v8::Handle<v8::String> source) { |
+ v8::EscapableHandleScope handle_scope(GetIsolate()); |
+ // Keep in order with the arguments in LoadAmdModule. |
+ v8::Handle<v8::String> left = |
+ v8::String::NewFromUtf8(GetIsolate(), "(function(define) {"); |
+ v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})"); |
+ return handle_scope.Escape(v8::Local<v8::String>( |
+ v8::String::Concat(left, v8::String::Concat(source, right)))); |
+} |
+ |
void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) { |
CHECK_EQ(1, args.Length()); |
CHECK(args[0]->IsObject()); |
@@ -586,4 +628,70 @@ void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) { |
args.GetReturnValue().Set(privates); |
} |
+void ModuleSystem::LoadAmdModule(const std::string& module_name) { |
+ v8::HandleScope handle_scope(GetIsolate()); |
+ v8::Context::Scope context_scope(context()->v8_context()); |
+ |
+ v8::Handle<v8::Value> source(GetSource(module_name)); |
+ if (source.IsEmpty() || source->IsUndefined()) { |
+ Fatal(context_, "No source for requireAsync(" + module_name + ")"); |
+ return; |
+ } |
+ v8::Handle<v8::String> wrapped_source( |
+ WrapAmdSource(v8::Handle<v8::String>::Cast(source))); |
+ // Modules are wrapped in (function(){...}) so they always return functions. |
+ v8::Handle<v8::Value> func_as_value = |
+ RunString(wrapped_source, |
+ v8::String::NewFromUtf8(GetIsolate(), module_name.c_str())); |
+ if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) { |
+ Fatal(context_, "Bad source for requireAsync(" + module_name + ")"); |
+ return; |
+ } |
not at google - send to devlin
2014/07/01 18:13:05
surely there is some code we can share with the sy
Sam McNally
2014/07/02 03:26:35
Done.
|
+ |
+ v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value); |
+ |
+ v8::Handle<v8::Object> define_object = v8::Object::New(GetIsolate()); |
+ gin::ModuleRegistry::InstallGlobals(GetIsolate(), define_object); |
+ |
+ // These must match the argument order in WrapAmdSource. |
+ v8::Handle<v8::Value> args[] = { |
+ define_object->Get(v8::String::NewFromUtf8(GetIsolate(), "define")), |
+ }; |
+ { |
+ v8::TryCatch try_catch; |
+ try_catch.SetCaptureMessage(true); |
+ context_->CallFunction(func, arraysize(args), args); |
+ if (try_catch.HasCaught()) { |
+ HandleException(try_catch); |
+ return; |
+ } |
+ } |
+} |
+ |
+void ModuleSystem::OnDidAddPendingModule( |
+ const std::string& id, |
+ const std::vector<std::string>& dependencies) { |
+ if (!source_map_->Contains(id)) |
+ return; |
+ |
+ gin::ModuleRegistry* registry = |
+ gin::ModuleRegistry::From(context_->v8_context()); |
+ for (std::vector<std::string>::const_iterator it = dependencies.begin(); |
+ it != dependencies.end(); |
+ ++it) { |
+ if (registry->available_modules().count(*it) == 0) |
+ LoadAmdModule(*it); |
+ } |
+ registry->AttemptToLoadMoreModules(GetIsolate()); |
+} |
+ |
+void ModuleSystem::OnModuleLoaded( |
+ scoped_ptr<v8::UniquePersistent<v8::Promise::Resolver> > resolver, |
+ v8::Handle<v8::Value> value) { |
+ v8::HandleScope handle_scope(GetIsolate()); |
+ v8::Handle<v8::Promise::Resolver> resolver_local( |
+ v8::Local<v8::Promise::Resolver>::New(GetIsolate(), *resolver)); |
not at google - send to devlin
2014/07/01 18:13:05
you should also check is_valid(). the C++ lifetime
Sam McNally
2014/07/02 03:26:35
Done.
|
+ resolver_local->Resolve(value); |
+} |
+ |
} // namespace extensions |