Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(417)

Side by Side Diff: extensions/renderer/module_system.cc

Issue 359413004: Add support for using AMD modules from extensions modules. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: extensions_renderer should depend on gin Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « extensions/renderer/module_system.h ('k') | extensions/renderer/script_context.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "extensions/renderer/module_system.h" 5 #include "extensions/renderer/module_system.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/debug/trace_event.h" 9 #include "base/debug/trace_event.h"
10 #include "base/stl_util.h" 10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h" 11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h" 12 #include "base/strings/stringprintf.h"
13 #include "content/public/renderer/render_view.h" 13 #include "content/public/renderer/render_view.h"
14 #include "extensions/common/extension_messages.h" 14 #include "extensions/common/extension_messages.h"
15 #include "extensions/common/extensions_client.h" 15 #include "extensions/common/extensions_client.h"
16 #include "extensions/renderer/console.h" 16 #include "extensions/renderer/console.h"
17 #include "extensions/renderer/safe_builtins.h" 17 #include "extensions/renderer/safe_builtins.h"
18 #include "extensions/renderer/script_context.h" 18 #include "extensions/renderer/script_context.h"
19 #include "gin/modules/module_registry.h"
19 #include "third_party/WebKit/public/web/WebFrame.h" 20 #include "third_party/WebKit/public/web/WebFrame.h"
20 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h" 21 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
21 22
22 namespace extensions { 23 namespace extensions {
23 24
24 namespace { 25 namespace {
25 26
26 const char* kModuleSystem = "module_system"; 27 const char* kModuleSystem = "module_system";
27 const char* kModuleName = "module_name"; 28 const char* kModuleName = "module_name";
28 const char* kModuleField = "module_field"; 29 const char* kModuleField = "module_field";
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 resource_name.c_str(), 115 resource_name.c_str(),
115 message->GetLineNumber(), 116 message->GetLineNumber(),
116 error_message.c_str()); 117 error_message.c_str());
117 } 118 }
118 119
119 ModuleSystem::ModuleSystem(ScriptContext* context, SourceMap* source_map) 120 ModuleSystem::ModuleSystem(ScriptContext* context, SourceMap* source_map)
120 : ObjectBackedNativeHandler(context), 121 : ObjectBackedNativeHandler(context),
121 context_(context), 122 context_(context),
122 source_map_(source_map), 123 source_map_(source_map),
123 natives_enabled_(0), 124 natives_enabled_(0),
124 exception_handler_(new DefaultExceptionHandler(context)) { 125 exception_handler_(new DefaultExceptionHandler(context)),
126 weak_factory_(this) {
125 RouteFunction( 127 RouteFunction(
126 "require", 128 "require",
127 base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this))); 129 base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this)));
128 RouteFunction( 130 RouteFunction(
129 "requireNative", 131 "requireNative",
130 base::Bind(&ModuleSystem::RequireNative, base::Unretained(this))); 132 base::Bind(&ModuleSystem::RequireNative, base::Unretained(this)));
133 RouteFunction(
134 "requireAsync",
135 base::Bind(&ModuleSystem::RequireAsync, base::Unretained(this)));
131 RouteFunction("privates", 136 RouteFunction("privates",
132 base::Bind(&ModuleSystem::Private, base::Unretained(this))); 137 base::Bind(&ModuleSystem::Private, base::Unretained(this)));
133 138
134 v8::Handle<v8::Object> global(context->v8_context()->Global()); 139 v8::Handle<v8::Object> global(context->v8_context()->Global());
135 v8::Isolate* isolate = context->isolate(); 140 v8::Isolate* isolate = context->isolate();
136 global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModulesField), 141 global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModulesField),
137 v8::Object::New(isolate)); 142 v8::Object::New(isolate));
138 global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModuleSystem), 143 global->SetHiddenValue(v8::String::NewFromUtf8(isolate, kModuleSystem),
139 v8::External::New(isolate, this)); 144 v8::External::New(isolate, this));
145
146 gin::ModuleRegistry::From(context->v8_context())->AddObserver(this);
140 } 147 }
141 148
142 ModuleSystem::~ModuleSystem() { Invalidate(); } 149 ModuleSystem::~ModuleSystem() { Invalidate(); }
143 150
144 void ModuleSystem::Invalidate() { 151 void ModuleSystem::Invalidate() {
145 if (!is_valid()) 152 if (!is_valid())
146 return; 153 return;
147 154
148 // Clear the module system properties from the global context. It's polite, 155 // Clear the module system properties from the global context. It's polite,
149 // and we use this as a signal in lazy handlers that we no longer exist. 156 // and we use this as a signal in lazy handlers that we no longer exist.
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 if (modules_value.IsEmpty() || modules_value->IsUndefined()) { 215 if (modules_value.IsEmpty() || modules_value->IsUndefined()) {
209 Warn(GetIsolate(), "Extension view no longer exists"); 216 Warn(GetIsolate(), "Extension view no longer exists");
210 return v8::Undefined(GetIsolate()); 217 return v8::Undefined(GetIsolate());
211 } 218 }
212 219
213 v8::Handle<v8::Object> modules(v8::Handle<v8::Object>::Cast(modules_value)); 220 v8::Handle<v8::Object> modules(v8::Handle<v8::Object>::Cast(modules_value));
214 v8::Local<v8::Value> exports(modules->Get(module_name)); 221 v8::Local<v8::Value> exports(modules->Get(module_name));
215 if (!exports->IsUndefined()) 222 if (!exports->IsUndefined())
216 return handle_scope.Escape(exports); 223 return handle_scope.Escape(exports);
217 224
218 std::string module_name_str = *v8::String::Utf8Value(module_name); 225 exports = LoadModule(*v8::String::Utf8Value(module_name));
219 v8::Handle<v8::Value> source(GetSource(module_name_str));
220 if (source.IsEmpty() || source->IsUndefined()) {
221 Fatal(context_, "No source for require(" + module_name_str + ")");
222 return v8::Undefined(GetIsolate());
223 }
224 v8::Handle<v8::String> wrapped_source(
225 WrapSource(v8::Handle<v8::String>::Cast(source)));
226 // Modules are wrapped in (function(){...}) so they always return functions.
227 v8::Handle<v8::Value> func_as_value = RunString(wrapped_source, module_name);
228 if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) {
229 Fatal(context_, "Bad source for require(" + module_name_str + ")");
230 return v8::Undefined(GetIsolate());
231 }
232
233 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value);
234
235 exports = v8::Object::New(GetIsolate());
236 v8::Handle<v8::Object> natives(NewInstance());
237 CHECK(!natives.IsEmpty()); // this can happen if v8 has issues
238
239 // These must match the argument order in WrapSource.
240 v8::Handle<v8::Value> args[] = {
241 // CommonJS.
242 natives->Get(v8::String::NewFromUtf8(
243 GetIsolate(), "require", v8::String::kInternalizedString)),
244 natives->Get(v8::String::NewFromUtf8(
245 GetIsolate(), "requireNative", v8::String::kInternalizedString)),
246 exports,
247 // Libraries that we magically expose to every module.
248 console::AsV8Object(),
249 natives->Get(v8::String::NewFromUtf8(
250 GetIsolate(), "privates", v8::String::kInternalizedString)),
251 // Each safe builtin. Keep in order with the arguments in WrapSource.
252 context_->safe_builtins()->GetArray(),
253 context_->safe_builtins()->GetFunction(),
254 context_->safe_builtins()->GetJSON(),
255 context_->safe_builtins()->GetObjekt(),
256 context_->safe_builtins()->GetRegExp(),
257 context_->safe_builtins()->GetString(), };
258 {
259 v8::TryCatch try_catch;
260 try_catch.SetCaptureMessage(true);
261 context_->CallFunction(func, arraysize(args), args);
262 if (try_catch.HasCaught()) {
263 HandleException(try_catch);
264 return v8::Undefined(GetIsolate());
265 }
266 }
267 modules->Set(module_name, exports); 226 modules->Set(module_name, exports);
268 return handle_scope.Escape(exports); 227 return handle_scope.Escape(exports);
269 } 228 }
270 229
271 v8::Local<v8::Value> ModuleSystem::CallModuleMethod( 230 v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
272 const std::string& module_name, 231 const std::string& module_name,
273 const std::string& method_name) { 232 const std::string& method_name) {
274 v8::HandleScope handle_scope(GetIsolate()); 233 v8::HandleScope handle_scope(GetIsolate());
275 v8::Handle<v8::Value> no_args; 234 v8::Handle<v8::Value> no_args;
276 return CallModuleMethod(module_name, method_name, 0, &no_args); 235 return CallModuleMethod(module_name, method_name, 0, &no_args);
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after
551 510
552 NativeHandlerMap::iterator i = native_handler_map_.find(native_name); 511 NativeHandlerMap::iterator i = native_handler_map_.find(native_name);
553 if (i == native_handler_map_.end()) { 512 if (i == native_handler_map_.end()) {
554 Fatal(context_, 513 Fatal(context_,
555 "Couldn't find native for requireNative(" + native_name + ")"); 514 "Couldn't find native for requireNative(" + native_name + ")");
556 return v8::Undefined(GetIsolate()); 515 return v8::Undefined(GetIsolate());
557 } 516 }
558 return i->second->NewInstance(); 517 return i->second->NewInstance();
559 } 518 }
560 519
520 void ModuleSystem::RequireAsync(
521 const v8::FunctionCallbackInfo<v8::Value>& args) {
522 CHECK_EQ(1, args.Length());
523 std::string module_name = *v8::String::Utf8Value(args[0]->ToString());
524 v8::Handle<v8::Promise::Resolver> resolver(
525 v8::Promise::Resolver::New(GetIsolate()));
526 args.GetReturnValue().Set(resolver->GetPromise());
527 scoped_ptr<v8::UniquePersistent<v8::Promise::Resolver> > persistent_resolver(
528 new v8::UniquePersistent<v8::Promise::Resolver>(GetIsolate(), resolver));
529 gin::ModuleRegistry* module_registry =
530 gin::ModuleRegistry::From(context_->v8_context());
531 if (!module_registry) {
532 Warn(GetIsolate(), "Extension view no longer exists");
533 resolver->Reject(v8::Exception::Error(v8::String::NewFromUtf8(
534 GetIsolate(), "Extension view no longer exists")));
535 return;
536 }
537 module_registry->LoadModule(GetIsolate(),
538 module_name,
539 base::Bind(&ModuleSystem::OnModuleLoaded,
540 weak_factory_.GetWeakPtr(),
541 base::Passed(&persistent_resolver)));
542 if (module_registry->available_modules().count(module_name) == 0)
543 LoadModule(module_name);
544 }
545
561 v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) { 546 v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) {
562 v8::EscapableHandleScope handle_scope(GetIsolate()); 547 v8::EscapableHandleScope handle_scope(GetIsolate());
563 // Keep in order with the arguments in RequireForJsInner. 548 // Keep in order with the arguments in RequireForJsInner.
564 v8::Handle<v8::String> left = v8::String::NewFromUtf8( 549 v8::Handle<v8::String> left = v8::String::NewFromUtf8(
565 GetIsolate(), 550 GetIsolate(),
566 "(function(require, requireNative, exports, " 551 "(function(define, require, requireNative, requireAsync, exports, "
567 "console, privates," 552 "console, privates,"
568 "$Array, $Function, $JSON, $Object, $RegExp, $String) {" 553 "$Array, $Function, $JSON, $Object, $RegExp, $String) {"
569 "'use strict';"); 554 "'use strict';");
570 v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})"); 555 v8::Handle<v8::String> right = v8::String::NewFromUtf8(GetIsolate(), "\n})");
571 return handle_scope.Escape(v8::Local<v8::String>( 556 return handle_scope.Escape(v8::Local<v8::String>(
572 v8::String::Concat(left, v8::String::Concat(source, right)))); 557 v8::String::Concat(left, v8::String::Concat(source, right))));
573 } 558 }
574 559
575 void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) { 560 void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) {
576 CHECK_EQ(1, args.Length()); 561 CHECK_EQ(1, args.Length());
577 CHECK(args[0]->IsObject()); 562 CHECK(args[0]->IsObject());
578 v8::Local<v8::Object> obj = args[0].As<v8::Object>(); 563 v8::Local<v8::Object> obj = args[0].As<v8::Object>();
579 v8::Local<v8::String> privates_key = 564 v8::Local<v8::String> privates_key =
580 v8::String::NewFromUtf8(GetIsolate(), "privates"); 565 v8::String::NewFromUtf8(GetIsolate(), "privates");
581 v8::Local<v8::Value> privates = obj->GetHiddenValue(privates_key); 566 v8::Local<v8::Value> privates = obj->GetHiddenValue(privates_key);
582 if (privates.IsEmpty()) { 567 if (privates.IsEmpty()) {
583 privates = v8::Object::New(args.GetIsolate()); 568 privates = v8::Object::New(args.GetIsolate());
584 obj->SetHiddenValue(privates_key, privates); 569 obj->SetHiddenValue(privates_key, privates);
585 } 570 }
586 args.GetReturnValue().Set(privates); 571 args.GetReturnValue().Set(privates);
587 } 572 }
588 573
574 v8::Handle<v8::Value> ModuleSystem::LoadModule(const std::string& module_name) {
575 v8::EscapableHandleScope handle_scope(GetIsolate());
576 v8::Context::Scope context_scope(context()->v8_context());
577
578 v8::Handle<v8::Value> source(GetSource(module_name));
579 if (source.IsEmpty() || source->IsUndefined()) {
580 Fatal(context_, "No source for require(" + module_name + ")");
581 return v8::Undefined(GetIsolate());
582 }
583 v8::Handle<v8::String> wrapped_source(
584 WrapSource(v8::Handle<v8::String>::Cast(source)));
585 // Modules are wrapped in (function(){...}) so they always return functions.
586 v8::Handle<v8::Value> func_as_value =
587 RunString(wrapped_source,
588 v8::String::NewFromUtf8(GetIsolate(), module_name.c_str()));
589 if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) {
590 Fatal(context_, "Bad source for require(" + module_name + ")");
591 return v8::Undefined(GetIsolate());
592 }
593
594 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_as_value);
595
596 v8::Handle<v8::Object> define_object = v8::Object::New(GetIsolate());
597 gin::ModuleRegistry::InstallGlobals(GetIsolate(), define_object);
598
599 v8::Local<v8::Value> exports = v8::Object::New(GetIsolate());
600 v8::Handle<v8::Object> natives(NewInstance());
601 CHECK(!natives.IsEmpty()); // this can happen if v8 has issues
602
603 // These must match the argument order in WrapSource.
604 v8::Handle<v8::Value> args[] = {
605 // AMD.
606 define_object->Get(v8::String::NewFromUtf8(GetIsolate(), "define")),
607 // CommonJS.
608 natives->Get(v8::String::NewFromUtf8(
609 GetIsolate(), "require", v8::String::kInternalizedString)),
610 natives->Get(v8::String::NewFromUtf8(
611 GetIsolate(), "requireNative", v8::String::kInternalizedString)),
612 natives->Get(v8::String::NewFromUtf8(
613 GetIsolate(), "requireAsync", v8::String::kInternalizedString)),
614 exports,
615 // Libraries that we magically expose to every module.
616 console::AsV8Object(),
617 natives->Get(v8::String::NewFromUtf8(
618 GetIsolate(), "privates", v8::String::kInternalizedString)),
619 // Each safe builtin. Keep in order with the arguments in WrapSource.
620 context_->safe_builtins()->GetArray(),
621 context_->safe_builtins()->GetFunction(),
622 context_->safe_builtins()->GetJSON(),
623 context_->safe_builtins()->GetObjekt(),
624 context_->safe_builtins()->GetRegExp(),
625 context_->safe_builtins()->GetString(),
626 };
627 {
628 v8::TryCatch try_catch;
629 try_catch.SetCaptureMessage(true);
630 context_->CallFunction(func, arraysize(args), args);
631 if (try_catch.HasCaught()) {
632 HandleException(try_catch);
633 return v8::Undefined(GetIsolate());
634 }
635 }
636 return handle_scope.Escape(exports);
637 }
638
639 void ModuleSystem::OnDidAddPendingModule(
640 const std::string& id,
641 const std::vector<std::string>& dependencies) {
642 if (!source_map_->Contains(id))
643 return;
644
645 gin::ModuleRegistry* registry =
646 gin::ModuleRegistry::From(context_->v8_context());
647 DCHECK(registry);
648 for (std::vector<std::string>::const_iterator it = dependencies.begin();
649 it != dependencies.end();
650 ++it) {
651 if (registry->available_modules().count(*it) == 0)
652 LoadModule(*it);
653 }
654 registry->AttemptToLoadMoreModules(GetIsolate());
655 }
656
657 void ModuleSystem::OnModuleLoaded(
658 scoped_ptr<v8::UniquePersistent<v8::Promise::Resolver> > resolver,
659 v8::Handle<v8::Value> value) {
660 if (!is_valid())
661 return;
662 v8::HandleScope handle_scope(GetIsolate());
663 v8::Handle<v8::Promise::Resolver> resolver_local(
664 v8::Local<v8::Promise::Resolver>::New(GetIsolate(), *resolver));
665 resolver_local->Resolve(value);
666 }
667
589 } // namespace extensions 668 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/renderer/module_system.h ('k') | extensions/renderer/script_context.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698