Closed ghost closed 9 years ago
well.. all what this does is it says if your system supports importing and exporting, it will export a value. I am not familiar with webpack can you explain more what happens when the export is invoked?
What it does is module and module.exports are defined, then the function getNodeSystem is executed and it search for node modules.
My problem is that I am in a browser, I have defined module and module.exports but as I am client side I have no node modules installed, then getNodeSystem execution failed.
If my module and module.exports properties were named different, I probably wouldn't have any problem, but I can't name them differently.
Did I give you enough information ?
so what would be a better condition to check for node but not run into webpack? currently it is:
typeof module !== "undefined" && module.exports
Pinging @csnover for this one. @csnover any insight on the correct check here that would work with node-like loaders e.g. browserfiy and webpack?
There isn’t any way to detect Node.js as a distinct environment any more because it isn’t. Electron and NW.js for example stick Node.js APIs into a browser context, where you have the ability to do script injection to load any code like a browser, but also you can call sync require
to load local code like Node.js.
So, all you can try to do as an author is attempt to infer that the APIs you actually are going to call exist, and then pray that they’re actually compatible. So if you are doing something like require('fs')
then some code like this:
function getFs() {
if (typeof require === 'function') {
try {
var fs = require('fs');
if (looksLikeFs(fs)) {
return fs;
}
}
catch (error) {
return null;
}
}
}
I’ll leave it up to you to try to figure out how to do it in a browser.
In the case of putting typescriptServices.js into webpack, it sounds like that’s simply not supported and if users want to bundle it with something else for use in the browser they need to use a straight concatenative approach instead of one that wraps the code with Node.js-ish APIs that confuse/defeat the environment detection.
@mhegazy @vladima @csnover thank you guys for the time you spent analyzing my problem and suggesting solutions.
I found a hack fitting my architecture in two steps : First, I exclude typescriptservices.js from web pack processing, thus, I avoid the failure of generating the production environment. Finally, I load the content of typescriptservices.js, create a new function which body is the content of the file and return the symbol I need.
It works, and avoid me having to patch typescriptservices.js :)
pinging @jbrantly.
@jbrantly any ideas here on loading issue with webpack?
This has been a fun one. I tried skirting around the issue in webpack using the official imports-loader
and exports-loader
but couldn't find a way to make it work. I was able to make it work using an unofficial loader called wrap-loader
.
// webpack.config.js
module: {
noParse: [/typescript.js$/],
loaders: [
{ test: require.resolve('typescript'), loader: "wrap?typescript" }
]
},
wrap: {
typescript: {
before: [
'var __module = module;',
'module = false;'
],
after: ['__module.exports = ts;']
}
}
// app.js
var typescript = require('typescript');
console.log(typescript.transpileModule('let foo = 0;', {compilerOptions: {}}).outputText)
This works by first making sure webpack does not parse TypeScript for require
by using the noParse
config. Secondly it wraps TypeScript, renaming module
so that the current node behavior doesn't get picked up but still allowing for an export at the end using the renamed variable.
Looking at this, I would say that it's weird that TypeScript uses the current typeof module !== "undefined" && module.exports
check for node. Really that check is for CommonJS compatibility, not node compatibility. I would suggest something like
typeof process !== "undefined" && !process.browser
That approach, in my mind, leans toward the current behavior while enabling compatibility with webpack and browserify. In node and most node-like environments, the node path will be taken, unless the node-like environment explicitly states that its in the browser (both webpack and browserify set process.browser).
One refinement: typeof process !== "undefined" && !process.browser
is probably too liberal and can pick up a stray process
variable. Probably also need a positive property check as @vladima proposed. LESS uses typeof process !== "undefined" && process.nextTick
for this purpose. Something like typeof process !== "undefined" && process.nextTick && !process.browser
seems reasonable to me. The first two conditions include all node-like environments and the last excludes webpack and browserify.
I am using typescript client side in a project managed using web pack.
When web pack processes typescriptServices.js, some part of the getNodeSystem code is evaluated because (typeof module !== "undefined" && module.exports) is true.
Evaluating the code, web pack finds some references to require calls and try to find modules, it fails to do so because I don't use node modules client side.
Is there a way for you to get rid of this problem ? Perhaps it is possible to split the library depending on if it is used client or server side ?