I want to bundle a Node.js script, which somewhere calls require(expression). After bundling the script with webpack, require fails. This is a super simplified example:
// main.js
const x = require(process.argv[2])
console.log(x)
I would like to either have a "normal" require for this case or tell webpack to include a specific file which I know will be required in the future (after bundling). To stick with this example, I know the value of process.argv[2] ahead of bundling.
Note: The code doing the expression based require is a dependency, so I cannot tweak require code.
This is my webpack.config.js
module.exports = {
entry: './test.js',
output: {
filename: 'test.js'
},
target: 'node'
}
The require path is relative to the file it is used in. So you'll need to figure out the path from where require is executing to the file it's loading from the parameter. Then prepend the relative part to the parameter.
Related
I want to natively require modules without using webpack requiring mechanism, i.e keeping require(..) as it without touch.
to achieve my goal I created a file called native-require.js with this content
module.exports = require;
and in webpack.config.js
module: {
noParse: /\/native-require.js$/,
}
now, in my script file I do:
let filePath = resolve(__dirname, `../config/file.js`);
let content = nativeRequire(filePath);
console.log(content)
it works fine in Linux but in windows I got the error Cannot find module 'D:\Downloads\config\file.js'
I also tried to remove the file extension from filePath
I don't want to lock my project to webpack-only using, I need my project to be able to run without webpact (for example using ts-node)
so I don't want to use webpack-specific variables such as __webpack_require__
I rewrote my server side code to use experimental esm imports. That means __dirname doesnt work anymore. To make this library consumable by non module code, I used webpack to transpile the code which strips all imports and bundles it together. However, to get around the __dirname problem, I have a cjs file that always gets loaded as commonjs module which only exports __dirname. However, webpack also bundles this file and destroys the meaning of __dirname (no matter which option you pass in the webpack config).
So my question: How can I convince webpack to just require this single file while bundling everything else?
The external option only seems to work for modules which are not loaded by path (like require('anyModule')) but not require('./somefile.js')
PS: The ignore plugin doesnt work. It just includes an error in the bundled file saying that the file cant be found
I got it to work with the external option by passing a function and filtering out that specific filename and replaced it with the correct path to the file:
externals: [ nodeModules, function (context, request, callback) {
if (/dirname.cjs/.test(request)) {
return callback(null, 'commonjs ./' + path.join('./', path.relative(__dirname, context), request).replace('\\', '/'))
}
callback()
} ]
I am not sure if this path juggling is needed but it gets the job done
I have a script that does some analysis on my source files and a part of that analysis is to require the file. Some of the files are in JSX format however and node does not understand this by default.
Is it possible to make it so that a file that looks like this:
function MyModule () {
return <div>hello</div>
}
module.exports = MyModule
is possible to require through require('./my-module')?
Use JSX as a template engine in Node
NPM Package : https://www.npmjs.com/package/jsx-node
To be able to simply require .jsx files, you need to tell Node what to do with them. Running the following code makes you able to require('./SomeFile.jsx'):
require('jsx-node').install({
replace: {
preact: 'jsx-node',
}
});
Warning:
This module is still in a very early phase. Any production use should be approached with caution.
For more Detail visit Link.
How can I make webpack skip occurences of
require('shelljs/global');
in my source files? I want to make a bundle of my source files but keep the require('shelljs/global') in the files and not bundle shelljs/global.
If you store the path in a variable then IgnorePlugin will not work. Though you still could do:
const myCustomModule = eval('require')(myCustomPath)
for new comers, on webpack 2+ the way to do this is like so:
module.exports = {
entry: __dirname + '/src/app',
output: {
path: __dirname + '/dist',
libraryTarget: 'umd'
},
externals: {
'shelljs/globals': 'commonjs shelljs/global'
}
};
the bundle will contain a verbatim require:
require('shelljs/global');
read on more supported formats on webpack's config guide and some good examples here
You can use Ignore Plugin (webpack 1) / Ignore plugin (webpack 2).
Add plugin in webpack.config.js:
plugins: [
new webpack.IgnorePlugin(/shelljs\/global/),
],
If require is in the global namespace and this is why you want Webpack to ignore it, just do window.require()
This should be a last resort option, but if you are certain that your JS file is always parsed by Webpack, and nothing else:
You could replace your require() calls with __non_webpack_require__()
Webpack will parse and convert any occurrence of this and output a normal require() call. This will only work if you are executing in NodeJS OR in a browser if you have a global require library available to trigger.
If webpack does not parse the file, and the script is run by something else, then your code will try to call the non-converted __non_webpack_require__ which will fail. You could potentially write some code that checks earlier in your script if __non_webpack_require__ exists as a function and if not, have it pass the call on to require.
However, this should be temporary, and only to just avoid the build errors, until you can replace it with something like Webpack's own dynamic imports.
Here a trick
const require = module[`require`].bind(module);
Note the use of a template string
If some files contains nested requires and You want to ignore them, You can tell webpack to not do parsing for these specific files.
For example if swiper.js and vue-quill-editor.js had inner requires this would be how to ignore them.
module.exports = {
module: {
noParse: [
/swiper.js/,/quill/
],
Architecture
I would like to share code between client and server side. I have defined aliases in the webpack config:
resolve: {
// Absolute paths: https://github.com/webpack/webpack/issues/109
alias: {
server : absPath('/src/server/'),
app : absPath('/src/app/'),
client : absPath('/src/client/'),
}
},
Problem
Now on the server side I need to include webpack in order to recognize the correct paths when I require a file. For example
require('app/somefile.js')
will fail in pure node.js because can't find the app folder.
What I need (read the What I need updated section)
I need to be able to use the webpack aliases. I was thinking about making a bundle of all the server part without any file from node_modules. In this way when the server starts it will use node_modules from the node_modules folder instead of a minified js file (Why? 1st: it doesn't work. 2nd: is bad, because node_modules are compiled based on platform. So I don't want my win files to go on a unix server).
Output:
Compiled server.js file without any node_modules included.
Let the server.js to use node_modules;
What I need updated
As I've noticed in https://github.com/webpack/webpack/issues/135 making a bundled server.js will mess up with all the io operation file paths.
A better idea would be to leave node.js server files as they are, but replace the require method provided with a custom webpack require which takes in account configurations such as aliases (others?)... Can be done how require.js has done to run on node.js server.
What I've tried
By adding this plugin in webpack
new webpack.optimize.CommonsChunkPlugin(/* chunkName= */"ignore", /* filename= */"server.bundle.js")
Entries:
entry: {
client: "./src/client/index.js",
server: "./src/server/index.js",
ignore: ['the_only_node_module'] // But I need to do that for every node_module
},
It will create a file server.js which only contains my server code. Then creates a server.bundle.js which is not used. But the problem is that webpack includes the webpackJsonp function in the server.bundle.js file. Therefore both the client and server will not work.
It should be a way to just disable node_modules on one entry.
What I've tried # 2
I've managed to exclude the path, but requires doesn't work because are already minified. So the source looks like require(3) instead of require('my-module'). Each require string has been converted to an integer so it doesn't work.
In order to work I also need to patch the require function that webpack exports to add the node.js native require function (this is easy manually, but should be done automatically).
What I've tried # 3
In the webpack configuration:
{target: "node"}
This only adds an exports variable (not sure about what else it does because I've diffed the output).
What I've tried # 4 (almost there)
Using
require.ensure('my_module')
and then replacing all occurrences of r(2).ensure with require. I don't know if the r(2) part is always the same and because of this might not be automated.
Solved
Thanks to ColCh for enlighten me on how to do here.
require = require('enhanced-require')(module, require('../../webpack.config'));
By changing the require method in node.js it will make node.js to pass all requires trough the webpack require function which allow us to use aliases and other gifts! Thanks ColCh!
Related
https://www.bountysource.com/issues/1660629-what-s-the-right-way-to-use-webpack-specific-functionality-in-node-js
https://github.com/webpack/webpack/issues/135
http://webpack.github.io/docs/configuration.html#target
https://github.com/webpack/webpack/issues/458
How to simultaneously create both 'web' and 'node' versions of a bundle with Webpack?
http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/
Thanks
Thanks to ColCh for enlighten me on how to do here.
require = require('enhanced-require')(module, require('../../webpack.config'));
By changing the require method in node.js it will make node.js to pass all requires trough the webpack require function which allow us to use aliases and other gifts! Thanks ColCh!
My solution was:
{
// make sure that webpack will externalize
// modules using Node's module API (CommonJS 2)
output: { ...output, libraryTarget: 'commonjs2' },
// externalize all require() calls to non-relative modules.
// Unless you do something funky, every time you import a module
// from node_modules, it should match the regex below
externals: /^[a-z0-9-]/,
// Optional: use this if you want to be able to require() the
// server bundles from Node.js later
target: 'node'
}