Skip to content
This repository
Browse code

Fixes #167, fixes an issue where a regular module circular dependency…

… behind a plugin load was not being resolved.
commit 20762872096677b3e6c27599d50a1a2cdf211e7b 1 parent 294e53f
James Burke authored
90 require.js
@@ -37,8 +37,13 @@ var requirejs, require, define;
37 37 interactiveScript = null,
38 38 checkLoadedDepth = 0,
39 39 useInteractive = false,
  40 + reservedDependencies = {
  41 + require: true,
  42 + module: true,
  43 + exports: true
  44 + },
40 45 req, cfg = {}, currentlyAddingScript, s, head, baseElement, scripts, script,
41   - src, subPath, mainScript, dataMain, i, ctx, jQueryCheck, checkLoadedTimeoutId;
  46 + src, subPath, mainScript, dataMain, globalI, ctx, jQueryCheck, checkLoadedTimeoutId;
42 47
43 48 function isFunction(it) {
44 49 return ostring.call(it) === "[object Function]";
@@ -874,15 +879,62 @@ var requirejs, require, define;
874 879 }
875 880 };
876 881
877   - function forceExec(manager, traced) {
878   - if (manager.isDone) {
879   - return undefined;
  882 + function findCycle(manager, traced) {
  883 + var fullName = manager.map.fullName,
  884 + depArray = manager.depArray,
  885 + fullyLoaded = true,
  886 + i, depName, depManager, result;
  887 +
  888 + if (manager.isDone || !fullName || !loaded[fullName]) {
  889 + return result;
  890 + }
  891 +
  892 + //Found the cycle.
  893 + if (traced[fullName]) {
  894 + return manager;
  895 + }
  896 +
  897 + traced[fullName] = true;
  898 +
  899 + //Trace through the dependencies.
  900 + if (depArray) {
  901 + for (i = 0; i < depArray.length; i++) {
  902 + //Some array members may be null, like if a trailing comma
  903 + //IE, so do the explicit [i] access and check if it has a value.
  904 + depName = depArray[i];
  905 + if (!loaded[depName] && !reservedDependencies[depName]) {
  906 + fullyLoaded = false;
  907 + break;
  908 + }
  909 + depManager = waiting[depName];
  910 + if (depManager && !depManager.isDone && loaded[depName]) {
  911 + result = findCycle(depManager, traced);
  912 + if (result) {
  913 + break;
  914 + }
  915 + }
  916 + }
  917 + if (!fullyLoaded) {
  918 + //Discard the cycle that was found, since it cannot
  919 + //be forced yet. Also clear this module from traced.
  920 + result = undefined;
  921 + delete traced[fullName];
  922 + }
880 923 }
881 924
  925 + return result;
  926 + }
  927 +
  928 + function forceExec(manager, traced) {
882 929 var fullName = manager.map.fullName,
883 930 depArray = manager.depArray,
884 931 i, depName, depManager, prefix, prefixManager, value;
885 932
  933 +
  934 + if (manager.isDone || !fullName || !loaded[fullName]) {
  935 + return undefined;
  936 + }
  937 +
886 938 if (fullName) {
887 939 if (traced[fullName]) {
888 940 return defined[fullName];
@@ -913,7 +965,7 @@ var requirejs, require, define;
913 965 }
914 966 }
915 967
916   - return fullName ? defined[fullName] : undefined;
  968 + return defined[fullName];
917 969 }
918 970
919 971 /**
@@ -926,8 +978,9 @@ var requirejs, require, define;
926 978 var waitInterval = config.waitSeconds * 1000,
927 979 //It is possible to disable the wait interval by using waitSeconds of 0.
928 980 expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
929   - noLoads = "", hasLoadedProp = false, stillLoading = false, prop,
930   - err, manager;
  981 + noLoads = "", hasLoadedProp = false, stillLoading = false,
  982 + onlyPluginResourceLoading = true,
  983 + i, prop, err, manager, cycleManager;
931 984
932 985 //If there are items still in the paused queue processing wait.
933 986 //This is particularly important in the sync case where each paused
@@ -957,7 +1010,15 @@ var requirejs, require, define;
957 1010 noLoads += prop + " ";
958 1011 } else {
959 1012 stillLoading = true;
960   - break;
  1013 + if (prop.indexOf('!') === -1) {
  1014 + onlyPluginResourceLoading = false;
  1015 + //No reason to keep looking for unfinished
  1016 + //loading. If the only stillLoading is a
  1017 + //plugin resource though, keep going,
  1018 + //because it may be that a plugin resource
  1019 + //is waiting on a non-plugin cycle.
  1020 + break;
  1021 + }
961 1022 }
962 1023 }
963 1024 }
@@ -976,7 +1037,11 @@ var requirejs, require, define;
976 1037 err.requireModules = noLoads;
977 1038 return req.onError(err);
978 1039 }
979   - if (stillLoading || context.scriptCount) {
  1040 +
  1041 + //If still waiting on loads, and the waiting load is something
  1042 + //other than a plugin resource, or there are still outstanding
  1043 + //scripts, then just try back later.
  1044 + if ((stillLoading && !onlyPluginResourceLoading) || context.scriptCount) {
980 1045 //Something is still waiting to load. Wait for it, but only
981 1046 //if a timeout is not already in effect.
982 1047 if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {
@@ -999,7 +1064,10 @@ var requirejs, require, define;
999 1064 if (context.waitCount) {
1000 1065 //Cycle through the waitAry, and call items in sequence.
1001 1066 for (i = 0; (manager = waitAry[i]); i++) {
1002   - forceExec(manager, {});
  1067 + if ((cycleManager = findCycle(manager, {}))) {
  1068 + forceExec(cycleManager, {});
  1069 + break;
  1070 + }
1003 1071 }
1004 1072
1005 1073 //If anything got placed in the paused queue, run it down.
@@ -1842,7 +1910,7 @@ var requirejs, require, define;
1842 1910 //Figure out baseUrl. Get it from the script tag with require.js in it.
1843 1911 scripts = document.getElementsByTagName("script");
1844 1912
1845   - for (i = scripts.length - 1; i > -1 && (script = scripts[i]); i--) {
  1913 + for (globalI = scripts.length - 1; globalI > -1 && (script = scripts[globalI]); globalI--) {
1846 1914 //Set the "head" where we can append children by
1847 1915 //using the script's parent.
1848 1916 if (!head) {
26 tests/all-server.js
@@ -39,19 +39,45 @@ var skipDohSetup = true,
39 39 load("doh/runner.js");
40 40 load('doh/_' + env + 'Runner.js');
41 41 load("simple-tests.js");
  42 +
  43 +delete requirejs.s.contexts._
42 44 load("circular-tests.js");
  45 +
  46 +delete requirejs.s.contexts._
43 47 load("relative/relative-tests.js");
  48 +
  49 +delete requirejs.s.contexts._
44 50 load("relative/relativeBaseUrl-tests.js");
  51 +
  52 +delete requirejs.s.contexts._
45 53 load("exports/exports-tests.js");
  54 +
  55 +delete requirejs.s.contexts._
46 56 load("exports/moduleAndExports-tests.js");
  57 +
  58 +delete requirejs.s.contexts._
47 59 load("anon/anon-tests.js");
  60 +
  61 +delete requirejs.s.contexts._
48 62 load("packages/packages-tests.js");
  63 +
  64 +delete requirejs.s.contexts._
49 65 load("plugins/sync-tests.js");
  66 +
  67 +delete requirejs.s.contexts._
50 68 load("plugins/fromText/fromText-tests.js");
  69 +
  70 +delete requirejs.s.contexts._
51 71 load("plugins/textDepend/textDepend-tests.js");
  72 +
  73 +delete requirejs.s.contexts._
52 74 load("universal/universal-tests.js");
  75 +
  76 +delete requirejs.s.contexts._
53 77 load("defineError/defineError-tests.js");
54 78
  79 +delete requirejs.s.contexts._
  80 +load("circular/circularPlugin-tests.js");
55 81
56 82 //Print out the final report
57 83 doh.run();
1  tests/all.js
@@ -27,6 +27,7 @@ if (location.href.indexOf('http://127.0.0.1/requirejs/') === 0) {
27 27
28 28
29 29 doh.registerUrl("circular", "../circular.html");
  30 +doh.registerUrl("circularPlugin", "../circular/circularPlugin.html");
30 31 doh.registerUrl("depoverlap", "../depoverlap.html");
31 32 doh.registerUrl("urlfetch", "../urlfetch/urlfetch.html");
32 33 doh.registerUrl("uniques", "../uniques/uniques.html");
4 tests/circular/a.js
... ... @@ -0,0 +1,4 @@
  1 +define(['b', 'exports'], function (b, exports) {
  2 + exports.name = 'a';
  3 + exports.b = b;
  4 +});
4 tests/circular/b.js
... ... @@ -0,0 +1,4 @@
  1 +define(['c', 'exports'], function (c, exports) {
  2 + exports.name = 'b';
  3 + exports.c = c;
  4 +});
4 tests/circular/c.js
... ... @@ -0,0 +1,4 @@
  1 +define(['a', 'exports'], function (a, exports) {
  2 + exports.name = 'c';
  3 + exports.a = a;
  4 +});
18 tests/circular/circularPlugin-tests.js
... ... @@ -0,0 +1,18 @@
  1 +require({
  2 + baseUrl: require.isBrowser ? './' : './circular'
  3 + },
  4 + ["require", "plugin!a"],
  5 + function(require, a) {
  6 + doh.register(
  7 + "circularPlugin",
  8 + [
  9 + function circularPlugin(t) {
  10 + t.is("a", a.name);
  11 + t.is("b", a.b.name);
  12 + t.is("c", a.b.c.name);
  13 + }
  14 + ]
  15 + );
  16 + doh.run();
  17 + }
  18 +);
19 tests/circular/circularPlugin.html
... ... @@ -0,0 +1,19 @@
  1 +<!DOCTYPE html>
  2 +<html>
  3 +<head>
  4 + <title>require.js: Circular Dependency under Plugin Test</title>
  5 + <script type="text/javascript" src="../../require.js"></script>
  6 + <script type="text/javascript" src="../doh/runner.js"></script>
  7 + <script type="text/javascript" src="../doh/_browserRunner.js"></script>
  8 + <script type="text/javascript" src="circularPlugin-tests.js"></script>
  9 +</head>
  10 +<body>
  11 + <h1>require.js: Circular Dependency under Plugin Test</h1>
  12 +
  13 + <p>Tests if a plugin that depends on a module with a circular dependency,
  14 + does the plugin get stuck as unresolved? In particular, can cycles be
  15 + broken when a plugin resource depedency is not loaded = true.</p>
  16 +
  17 + <p>Check console for messages</p>
  18 +</body>
  19 +</html>
5 tests/circular/plugin.js
... ... @@ -0,0 +1,5 @@
  1 +define({
  2 + load: function (name, require, load, config) {
  3 + require([name], load);
  4 + }
  5 +});

0 comments on commit 2076287

Please sign in to comment.
Something went wrong with that request. Please try again.