New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
require.resolveWeak does not have the same static resolution capabilities as import, require, etc #4993
Comments
Here's another example: const name = foo ? 'Example' : 'Loading'
import(/* webpackChunkName: "[request]" */ `./${name}`))
require.resolveWeak(`./${name}`) The transpiled code is: var name = foo ? 'Example' : 'Loading';
__webpack_require__("./src/components lazy recursive ^\\.\\/.*$")("./" + name)
/*require.resolve*/(__webpack_require__("./src/components recursive ^\\.\\/.*$").resolve("./" + name)) The differences are the word "lazy" and the fact that It seems possibly the new https://webpack.js.org/guides/code-splitting-async/#chunk-names Is there an updated version of
|
Also, to be clear, I have my split bundles and bootstrap code properly setup, eg: <script type='text/javascript' src='/static/bootstrap.js'></script>
<script type='text/javascript' src='/static/0.js'></script>
<script type='text/javascript' src='/static/main.js'></script> So The fact that it works server-side where the |
primarily because of all your hardwork on Webpack these last few years, I was able to bring the code-splitting [+ SSR] thing full circle: check it out. I put your magic comments to use as part of a complete server-side flushing system. I hope you like it and approve. I was aiming to come up with the most idiomatic solution. Also, if and when this issue is fixed I plan on releasing another article about using HoCs with universal components + universal rendering. See, with this issue fixed, we can now have dynamic universal components, not just one. That's a very important piece to this puzzle. In fact, it's the final piece. ps. I'm also the guy behind the Extract Css Chunks Webpack Plugin: https://github.com/faceyspacey/extract-css-chunks-webpack-plugin I know in the past u didn't like HMR with that plugin. But the thing is this is all part of the code-splitting + SSR dream. This all needs to be frictionless. There's no issues with my fork, except a warning I'd like to get rid of. Because of the way HMR works, the first change u make always gives a warning that might lead u to think HMR won't work. It in fact does, but the warning is disconcerting. I'm sure it's because of the way I hacked this together, which is why its creator really should be involved to make the official version. I can help. But basically after looking at what I've done u'll probably know exactly what to do. Anyway, it's a new future. Code Splitting + SSR is complete. Thank you. |
I found this issue breaks silently my application giving me "TypeError: Cannot read property 'call' of undefined" when I try to reach one of my react application routes. If I don't try to navigate to a route it works ok. For sure when I navigate to a route it uses resolveWeak and there it breaks. I found that if I disable CommonsChunkPlugin it work ok so I think it has something to be with that. Hope my experience helps to push this forward. It started to happen like a week ago or so, maybe with some dependency update. I use Webpack 2; Any other information I can give to help just ask me. |
this bug and #4812 are duplicates FYI. @sokra ? it seemed before, u planned not to make I sure hope so. Or at least a suggested alternative for the use case of a synchronous fallback. |
I've been diving into the Webpack code and seeing if I can fix it. It's no doubt an intimidating codebase to start with. The location I've come up with is this:
It seems because there is no /*require.resolve*/(__webpack_require__("./src/components recursive ^\\.\\/.*$").resolve("./" + name)) i.e. it's missing the __webpack_require__("./src/components lazy recursive ^\\.\\/.*$")("./" + name) Obviously there is more it, as it does receive some sort of comment.. And it also gets the @TheLarkInn any word? I'm not sure if my help is worth a damn, but I'm more than willing to try. A few words from somebody who knows how this stuff works could go a long way. |
actually my bad, it's not a comment it's meant to receive. But it seems like it's around here where |
the culprit file seems to be this one in fact: basically the files in the |
|
After debugging the Webpack compiler, the issue is that the For example, but If it did, the getSyncSource(dependencies, id) {
const map = this.getUserRequestMap(dependencies);
return `var map = ${JSON.stringify(map, null, "\t")};
function webpackContext(req) {
return __webpack_require__(webpackContextResolve(req));
};
function webpackContextResolve(req) {
var id = map[req];
if(!(id + 1)) // check for number or string
throw new Error("Cannot find module '" + req + "'.");
return id;
};
webpackContext.keys = function webpackContextKeys() {
return Object.keys(map);
};
webpackContext.resolve = webpackContextResolve;
module.exports = webpackContext;
webpackContext.id = ${JSON.stringify(id)};`;
} I'm trying to figure out now how to mark the expression to use the |
So basically it's about making var map = {
"./App": [
34
],
"./App.js": [
34
],
"./Example": [
135,
0
],
"./Example.js": [
135,
0
]
};
function webpackAsyncContext(req) {
var ids = map[req];
if(!ids)
return Promise.reject(new Error("Cannot find module '" + req + "'."));
return Promise.all(ids.slice(1).map(__webpack_require__.e)).then(function() {
return __webpack_require__(ids[0]);
});
};
webpackAsyncContext.keys = function webpackAsyncContextKeys() {
return Object.keys(map);
};
module.exports = webpackAsyncContext;
webpackAsyncContext.id = 372;
/***/ }), So it's not like it can't easily be done. For a resolveWeak context module, the result code would have a var map = {
"./App": 34,
"./App.js": 34,
"./Example": 135,
"./Example.js": 135,
}
module.resolve = function(key) {
return map[key]
}; |
the latest thinking is to create the equivalent of /***/ }),
/* 370 */
/***/ (function(module, exports, __webpack_require__) {
var map = {
"./Example.js": 78,
"./Foo.js": 79
};
function webpackContext(req) {
return __webpack_require__(webpackContextResolve(req));
};
function webpackContextResolve(req) {
var id = map[req];
if(!(id + 1)) // check for number or string
throw new Error("Cannot find module '" + req + "'.");
return id;
};
webpackContext.keys = function webpackContextKeys() {
return Object.keys(map);
};
webpackContext.resolve = webpackContextResolve;
module.exports = webpackContext;
webpackContext.id = 370; That's what |
Ok I finally figured it out. Basically, in if(this.async === "weak-context") {
// usually this assigns to this.dependencies, but that would actually bundle them
this.weakDependencies = weakDependencies;
// copied from "lazy" async mode:
dependencies.forEach((dep, idx) => {
let chunkName = this.chunkName;
if(chunkName) {
if(!/\[(index|request)\]/.test(chunkName))
chunkName += "[index]";
chunkName = chunkName.replace(/\[index\]/g, idx);
chunkName = chunkName.replace(/\[request\]/g, Template.toPath(dep.userRequest));
}
const block = new AsyncDependenciesBlock(chunkName, dep.module, dep.loc);
block.addDependency(dep);
this.addBlock(block);
});
} else if(this.async === "lazy-once") {... ...then when it comes to getting the source string we do this: getSourceString(asyncMode, outputOptions, requestShortener) {
if(asyncMode === 'weak-context') {
return this.getSyncSource(this.weakDependencies, this.id);
}
else if(asyncMode === "lazy") {... and we also gotta parse the arguments: module.exports = class RequireContextDependencyParserPlugin {
apply(parser) {
parser.plugin("call require.context", expr => {
let regExp = /^\.\/.*$/;
let recursive = true;
let weak = false
let chunkName
switch(expr.arguments.length) {
case 5:
{
const chunkNameExpr = parser.evaluateExpression(expr.arguments[4]);
if(!chunkNameExpr.isString()) return;
chunkName = chunkNameExpr.string;
}
case 4:
{
const weakExpr = parser.evaluateExpression(expr.arguments[3]);
if(!weakExpr.isBoolean()) return;
weak = weakExpr.bool;
}
case 3:
{
const regExpExpr = parser.evaluateExpression(expr.arguments[2]);
if(!regExpExpr.isRegExp()) return;
regExp = regExpExpr.regExp;
}
// falls through
case 2:
{
const recursiveExpr = parser.evaluateExpression(expr.arguments[1]);
if(!recursiveExpr.isBoolean()) return;
recursive = recursiveExpr.bool;
}
// falls through
case 1:
{
const requestExpr = parser.evaluateExpression(expr.arguments[0]);
if(!requestExpr.isString()) return;
const dep = new RequireContextDependency(requestExpr.string, recursive, regExp, chunkName, expr.range);
dep.loc = expr.loc;
dep.optional = parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
}
}
});
}
}; and: class RequireContextDependency extends ContextDependency {
constructor(request, recursive, regExp, weak, chunkName, range) {
super(request, recursive, regExp);
this.range = range;
if (weak) {
this.async = 'weak-context'
this.chunkName = chunkName
}
}
get type() {
return "require.context";
}
} ...So that allows us to create a weak context today via: require.context('./asyncComponents', true, /^\.\/.*$/, true, 'asyncComponents/[request]') or something like that, with the final option indicating to create a weak context. Perhaps in the end it's another function like Either way, that basically solves the problem. If we want to go further, we make the template for |
And here's the PR: |
Do you want to request a feature or report a bug?
BUG
What is the current behavior?
require.resolveWeak()
can't statically determine module string passed to it as well asimport().then
.modules[moduleId] is undefined here:
Here's the trace:
If the current behavior is a bug, please provide the steps to reproduce.
For example, try:
What is the expected behavior?
The expected behavior is that
resolveWeak
will return themoduleId
of the corresponding module. The weird thing is that it works when using Webpack on the server, but in the browser (Chrome) it does not work.In addition, the following works:
If this is a feature request, what is motivation or use case for changing the behavior?
The motivation and use case for this is for tools like React Loadable and React Universal Component which allow for async-loading + server-side rendering of the same component. Currently such tools don't allow for dynamic component selection (because it depends on
resolveWeak
for synchronous loading if the module is already available).If it was just a case of using
import().then
, such expressions would work. ButresolveWeak
is needed to make the server-side synchronous rendering magic happen, as well as the synchronous rendering on initial load in the browser if the corresponding chunks are embedded beforemain
.This is a very important feature for the React Loadable and React Universal Component community and any other future async packages.
Please mention other relevant information such as the browser version, Node.js version, webpack version and Operating System.
VERSION: 2.6.1 + 3.0.0
NODE: 7.7.2
OSX
The text was updated successfully, but these errors were encountered: