https://bugs.webkit.org/show_bug.cgi?id=166987
Reviewed by Sam Weinig.
Source/WebCore:
As discussed on https://github.com/whatwg/html/pull/2261, we should have
the way to suppress classic script execution when our user agent have
modules support. With such a feature, developers can write the code like,
<script type="module" src="./app.js"></script>
<script nomodule src="./bundled-app.js"></script>
In the above code, if the user agent does not support modules, the bundled-app.js
will be executed. On the other hand, if the user agent supports modules, we should
ignore the script tag which has the `nomodule` attribute.
This way allows us to support the legacy browsers while using modules.
In WebKit, we already support modules. Thus, we should ignore the classic script
attributed `nomodule`.
We also rename asyncAttributeValue and deferAttributeValue to hasAsyncAttribute and
hasDeferAttribute.
Tests: js/dom/modules/nomodule-has-no-effect-on-module-inline.html
js/dom/modules/nomodule-has-no-effect-on-module-src.html
js/dom/modules/nomodule-prevents-execution-classic-script-inline.html
js/dom/modules/nomodule-prevents-execution-classic-script-src.html
* dom/ScriptElement.cpp:
(WebCore::ScriptElement::prepareScript):
* dom/ScriptElement.h:
* html/HTMLAttributeNames.in:
* html/HTMLScriptElement.cpp:
(WebCore::HTMLScriptElement::hasAsyncAttribute):
(WebCore::HTMLScriptElement::hasDeferAttribute):
(WebCore::HTMLScriptElement::hasNoModuleAttribute):
(WebCore::HTMLScriptElement::asyncAttributeValue): Deleted.
(WebCore::HTMLScriptElement::deferAttributeValue): Deleted.
* html/HTMLScriptElement.h:
* html/HTMLScriptElement.idl:
* svg/SVGScriptElement.cpp:
(WebCore::SVGScriptElement::hasAsyncAttribute):
(WebCore::SVGScriptElement::hasDeferAttribute):
(WebCore::SVGScriptElement::hasNoModuleAttribute):
(WebCore::SVGScriptElement::asyncAttributeValue): Deleted.
(WebCore::SVGScriptElement::deferAttributeValue): Deleted.
* svg/SVGScriptElement.h:
LayoutTests:
* js/dom/modules/nomodule-dynamic-classic-inline-expected.txt: Added.
* js/dom/modules/nomodule-dynamic-classic-inline.html: Added.
* js/dom/modules/nomodule-dynamic-classic-src-expected.txt: Added.
* js/dom/modules/nomodule-dynamic-classic-src.html: Added.
* js/dom/modules/nomodule-has-no-effect-on-module-inline-expected.txt: Added.
* js/dom/modules/nomodule-has-no-effect-on-module-inline.html: Added.
* js/dom/modules/nomodule-has-no-effect-on-module-src-expected.txt: Added.
* js/dom/modules/nomodule-has-no-effect-on-module-src.html: Added.
* js/dom/modules/nomodule-prevents-execution-classic-script-inline-expected.txt: Added.
* js/dom/modules/nomodule-prevents-execution-classic-script-inline.html: Added.
* js/dom/modules/nomodule-prevents-execution-classic-script-src-expected.txt: Added.
* js/dom/modules/nomodule-prevents-execution-classic-script-src.html: Added.
* js/dom/modules/nomodule-reflect-expected.txt: Added.
* js/dom/modules/nomodule-reflect.html: Added.
* js/dom/modules/script-tests/error-classic-script.js: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@211078
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2017-01-15 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ Add the support for nomodule attribute on script element
+ https://bugs.webkit.org/show_bug.cgi?id=166987
+
+ Reviewed by Sam Weinig.
+
+ * js/dom/modules/nomodule-dynamic-classic-inline-expected.txt: Added.
+ * js/dom/modules/nomodule-dynamic-classic-inline.html: Added.
+ * js/dom/modules/nomodule-dynamic-classic-src-expected.txt: Added.
+ * js/dom/modules/nomodule-dynamic-classic-src.html: Added.
+ * js/dom/modules/nomodule-has-no-effect-on-module-inline-expected.txt: Added.
+ * js/dom/modules/nomodule-has-no-effect-on-module-inline.html: Added.
+ * js/dom/modules/nomodule-has-no-effect-on-module-src-expected.txt: Added.
+ * js/dom/modules/nomodule-has-no-effect-on-module-src.html: Added.
+ * js/dom/modules/nomodule-prevents-execution-classic-script-inline-expected.txt: Added.
+ * js/dom/modules/nomodule-prevents-execution-classic-script-inline.html: Added.
+ * js/dom/modules/nomodule-prevents-execution-classic-script-src-expected.txt: Added.
+ * js/dom/modules/nomodule-prevents-execution-classic-script-src.html: Added.
+ * js/dom/modules/nomodule-reflect-expected.txt: Added.
+ * js/dom/modules/nomodule-reflect.html: Added.
+ * js/dom/modules/script-tests/error-classic-script.js: Added.
+
2017-01-23 Gyuyoung Kim <gyuyoung.kim@webkit.org>
[EFL] Update timeout tests in media/modern-media-controls
--- /dev/null
+Test dynamic inlined classic script with nomodule.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS executed is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description('Test dynamic inlined classic script with nomodule.');
+window.executed = false;
+
+// Module will be executed asynchronously.
+window.jsTestIsAsync = true;
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+<script>
+(function () {
+ var element = document.createElement("script");
+ element.noModule = true;
+ element.textContent = `
+ testFailed('error');
+ window.executed = true;
+ `;
+ document.body.appendChild(element);
+ setTimeout(function () {
+ shouldBeFalse(`executed`);
+ finishJSTest();
+ }, 100);
+} ());
+</script>
+</body>
+</html>
--- /dev/null
+Test dynamic "src" classic script with nomodule.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS executed is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description('Test dynamic "src" classic script with nomodule.');
+window.executed = false;
+
+// Module will be executed asynchronously.
+window.jsTestIsAsync = true;
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+<script>
+(function () {
+ var element = document.createElement('script');
+ element.noModule = true;
+ element.src = './script-tests/error-classic-script.js';
+ document.body.appendChild(element);
+ setTimeout(function () {
+ shouldBeFalse(`executed`);
+ finishJSTest();
+ }, 100);
+}());
+</script>
+</body>
+</html>
--- /dev/null
+Test nomodule does not have any effect on module script.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Module is not executed yet.
+Module execution is confined in the module environment.
+PASS typeof cocoa is "undefined"
+PASS typeof exportedCocoa is "object"
+PASS exportedCocoa.taste() is "awesome"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description('Test nomodule does not have any effect on module script.');
+
+// Module will be executed asynchronously.
+window.jsTestIsAsync = true;
+</script>
+<script>
+debug('Module is not executed yet.');
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+<script nomodule type="module">
+import Cocoa from "./script-tests/module-inline-simple.js";
+var cocoa = new Cocoa();
+
+debug("Module execution is confined in the module environment.");
+shouldBeEqualToString("typeof cocoa", "undefined");
+
+window.exportedCocoa = cocoa;
+shouldBeEqualToString("typeof exportedCocoa", "object");
+shouldBeEqualToString("exportedCocoa.taste()", "awesome");
+finishJSTest();
+</script>
+</body>
+</html>
--- /dev/null
+Test nomodule does not have any effect on module script.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Module is not executed yet.
+Module execution is confined in the module environment.
+PASS typeof cocoa is "undefined"
+PASS typeof exportedCocoa is "object"
+PASS exportedCocoa.taste() is "nice"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description('Test nomodule does not have any effect on module script.');
+
+// Module will be executed asynchronously.
+window.jsTestIsAsync = true;
+</script>
+<script>
+debug('Module is not executed yet.');
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+<script nomodule type="module" src="./script-tests/module-src-simple.js"></script>
+</body>
+</html>
--- /dev/null
+Test nomodule prevents execution of classic script.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS executed is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description('Test nomodule prevents execution of classic script.');
+window.executed = false;
+</script>
+<script nomodule>
+window.executed = true;
+testFailed("error");
+</script>
+<script>
+shouldBeFalse(`executed`);
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+Test nomodule prevents execution of classic script.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS executed is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description('Test nomodule prevents execution of classic script.');
+window.executed = false;
+</script>
+<script nomodule src="./script-tests/module-src-simple.js"></script>
+<script>
+shouldBeFalse(`executed`);
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+Test dynamic "src" classic script with nomodule.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS element.noModule is true
+PASS executed is false
+PASS element.noModule is false
+PASS executed2 is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description('Test dynamic "src" classic script with nomodule.');
+window.executed = false;
+window.executed2 = false;
+
+// Module will be executed asynchronously.
+window.jsTestIsAsync = true;
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+<script id="target" src="./script-tests/error-classic-script.js" nomodule></script>
+<script id="target2">
+window.executed2 = true;
+</script>
+<script>
+window.element = null;
+(function () {
+ {
+ element = document.getElementById('target');
+ shouldBeTrue(`element.noModule`);
+ shouldBeFalse(`executed`);
+ }
+ {
+ element = document.getElementById('target2');
+ shouldBeFalse(`element.noModule`);
+ shouldBeTrue(`executed2`);
+ }
+ finishJSTest();
+}());
+</script>
+</body>
+</html>
--- /dev/null
+window.executed = true;
+testFailed("error");
+
+2017-01-15 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ Add the support for nomodule attribute on script element
+ https://bugs.webkit.org/show_bug.cgi?id=166987
+
+ Reviewed by Sam Weinig.
+
+ As discussed on https://github.com/whatwg/html/pull/2261, we should have
+ the way to suppress classic script execution when our user agent have
+ modules support. With such a feature, developers can write the code like,
+
+ <script type="module" src="./app.js"></script>
+ <script nomodule src="./bundled-app.js"></script>
+
+ In the above code, if the user agent does not support modules, the bundled-app.js
+ will be executed. On the other hand, if the user agent supports modules, we should
+ ignore the script tag which has the `nomodule` attribute.
+ This way allows us to support the legacy browsers while using modules.
+
+ In WebKit, we already support modules. Thus, we should ignore the classic script
+ attributed `nomodule`.
+
+ We also rename asyncAttributeValue and deferAttributeValue to hasAsyncAttribute and
+ hasDeferAttribute.
+
+ Tests: js/dom/modules/nomodule-has-no-effect-on-module-inline.html
+ js/dom/modules/nomodule-has-no-effect-on-module-src.html
+ js/dom/modules/nomodule-prevents-execution-classic-script-inline.html
+ js/dom/modules/nomodule-prevents-execution-classic-script-src.html
+
+ * dom/ScriptElement.cpp:
+ (WebCore::ScriptElement::prepareScript):
+ * dom/ScriptElement.h:
+ * html/HTMLAttributeNames.in:
+ * html/HTMLScriptElement.cpp:
+ (WebCore::HTMLScriptElement::hasAsyncAttribute):
+ (WebCore::HTMLScriptElement::hasDeferAttribute):
+ (WebCore::HTMLScriptElement::hasNoModuleAttribute):
+ (WebCore::HTMLScriptElement::asyncAttributeValue): Deleted.
+ (WebCore::HTMLScriptElement::deferAttributeValue): Deleted.
+ * html/HTMLScriptElement.h:
+ * html/HTMLScriptElement.idl:
+ * svg/SVGScriptElement.cpp:
+ (WebCore::SVGScriptElement::hasAsyncAttribute):
+ (WebCore::SVGScriptElement::hasDeferAttribute):
+ (WebCore::SVGScriptElement::hasNoModuleAttribute):
+ (WebCore::SVGScriptElement::asyncAttributeValue): Deleted.
+ (WebCore::SVGScriptElement::deferAttributeValue): Deleted.
+ * svg/SVGScriptElement.h:
+
2017-01-23 Joseph Pecoraro <pecoraro@apple.com>
Web Inspector: Provide a way to trigger a Garbage Collection
} else
wasParserInserted = false;
- if (wasParserInserted && !asyncAttributeValue())
+ if (wasParserInserted && !hasAsyncAttribute())
m_forceAsync = true;
// FIXME: HTML5 spec says we should check that all children are either comments or empty text nodes.
if (!document.frame())
return false;
+ if (scriptType == ScriptType::Classic && hasNoModuleAttribute())
+ return false;
+
if (!document.frame()->script().canExecuteScripts(AboutToExecuteScript))
return false;
// is handled as the same to the external module script.
bool isClassicExternalScript = scriptType == ScriptType::Classic && hasSourceAttribute();
- bool isParserInsertedDeferredScript = ((isClassicExternalScript && deferAttributeValue()) || scriptType == ScriptType::Module)
- && m_parserInserted && !asyncAttributeValue();
+ bool isParserInsertedDeferredScript = ((isClassicExternalScript && hasDeferAttribute()) || scriptType == ScriptType::Module)
+ && m_parserInserted && !hasAsyncAttribute();
if (isParserInsertedDeferredScript) {
m_willExecuteWhenDocumentFinishedParsing = true;
m_willBeParserExecuted = true;
- } else if (isClassicExternalScript && m_parserInserted && !asyncAttributeValue()) {
+ } else if (isClassicExternalScript && m_parserInserted && !hasAsyncAttribute()) {
ASSERT(scriptType == ScriptType::Classic);
m_willBeParserExecuted = true;
- } else if ((isClassicExternalScript || scriptType == ScriptType::Module) && !asyncAttributeValue() && !m_forceAsync) {
+ } else if ((isClassicExternalScript || scriptType == ScriptType::Module) && !hasAsyncAttribute() && !m_forceAsync) {
m_willExecuteInOrder = true;
ASSERT(m_loadableScript);
document.scriptRunner()->queueScriptForExecution(*this, *m_loadableScript, ScriptRunner::IN_ORDER_EXECUTION);
} else if (hasSourceAttribute() || scriptType == ScriptType::Module) {
ASSERT(m_loadableScript);
- ASSERT(asyncAttributeValue() || m_forceAsync);
+ ASSERT(hasAsyncAttribute() || m_forceAsync);
document.scriptRunner()->queueScriptForExecution(*this, *m_loadableScript, ScriptRunner::ASYNC_EXECUTION);
} else if (!hasSourceAttribute() && m_parserInserted && !document.haveStylesheetsLoaded()) {
ASSERT(scriptType == ScriptType::Classic);
virtual String languageAttributeValue() const = 0;
virtual String forAttributeValue() const = 0;
virtual String eventAttributeValue() const = 0;
- virtual bool asyncAttributeValue() const = 0;
- virtual bool deferAttributeValue() const = 0;
+ virtual bool hasAsyncAttribute() const = 0;
+ virtual bool hasDeferAttribute() const = 0;
virtual bool hasSourceAttribute() const = 0;
+ virtual bool hasNoModuleAttribute() const = 0;
Element& m_element;
WTF::OrdinalNumber m_startLineNumber;
muted
name
nohref
+nomodule
nonce
noresize
noshade
return attributeWithoutSynchronization(eventAttr).string();
}
-bool HTMLScriptElement::asyncAttributeValue() const
+bool HTMLScriptElement::hasAsyncAttribute() const
{
return hasAttributeWithoutSynchronization(asyncAttr);
}
-bool HTMLScriptElement::deferAttributeValue() const
+bool HTMLScriptElement::hasDeferAttribute() const
{
return hasAttributeWithoutSynchronization(deferAttr);
}
+bool HTMLScriptElement::hasNoModuleAttribute() const
+{
+ return hasAttributeWithoutSynchronization(nomoduleAttr);
+}
+
bool HTMLScriptElement::hasSourceAttribute() const
{
return hasAttributeWithoutSynchronization(srcAttr);
String languageAttributeValue() const final;
String forAttributeValue() const final;
String eventAttributeValue() const final;
- bool asyncAttributeValue() const final;
- bool deferAttributeValue() const final;
+ bool hasAsyncAttribute() const final;
+ bool hasDeferAttribute() const final;
+ bool hasNoModuleAttribute() const final;
bool hasSourceAttribute() const final;
void dispatchLoadEvent() final;
[Reflect] attribute DOMString type;
attribute DOMString? crossOrigin;
[Reflect] attribute DOMString nonce;
+ [Reflect] attribute boolean noModule;
};
return String();
}
-bool SVGScriptElement::asyncAttributeValue() const
+bool SVGScriptElement::hasAsyncAttribute() const
{
return false;
}
-bool SVGScriptElement::deferAttributeValue() const
+bool SVGScriptElement::hasDeferAttribute() const
+{
+ return false;
+}
+
+bool SVGScriptElement::hasNoModuleAttribute() const
{
return false;
}
String languageAttributeValue() const final;
String forAttributeValue() const final;
String eventAttributeValue() const final;
- bool asyncAttributeValue() const final;
- bool deferAttributeValue() const final;
+ bool hasAsyncAttribute() const final;
+ bool hasDeferAttribute() const final;
+ bool hasNoModuleAttribute() const final;
bool hasSourceAttribute() const final;
void dispatchLoadEvent() final { SVGExternalResourcesRequired::dispatchLoadEvent(this); }