Conditional require file in webpack - javascript

I want to bundle the files into my production build only if it is not for DEBUG;
So I've use webpack.DefinePlugin and set the variable DEBUG === true.
Also config webpack.UglifyJsPlugin with default options
And in the js file, I do like this:
const A = DEBUG === true ? null : require('./some-debug.js');
//do things with A, for example
console.log(A)
I checked the final bundle file, A is replaced with null (so DefinePlugin is working fine), but the content of some-debug.js file is still in the bundle js.
Is it possible to let webpack not require the file?
ps:
I think I can use resolve.alias to resolve './some-debug.js' --> undefined. But I want to keep my webpack.config.js generic, dont' want to apply too many resolve.alias entries.
Thanks

It doesn't work with ternary operator.
let A;
if (DEBUG === true) {
A = require('./some-debug.js');
}

Related

Webpack CopyPlugin modifying JS Files

I'm working on a React app being served by Flask.
I need the app to present some things that are filled by the Flask app using a Jinja template, and the simplest way I could find that should work is to use an external js file which I run through a render_template command and have the rest of the code reference that.
I used the WebpackCopyPlugin to make sure that file is available to import, and I explicitly exclude it from the babel-loader to make sure it doesn't get compiled.
However, when it is copied to the output dir by npm run build, it changes its contents!
This is the original file:
var is_admin = "{{is_admin}}" == "True";
var is_user = "{{is_user}}" == "True";
var is_debug = "{{is_debug}}" == "True";
var username = "{{request.remote_user}}";
(Yes, I know I shouldn't be keeping stuff like that in a javascript file, it doesn't actually give permissions to do anything - it's just for display purposes. The actual permission checking and access granting is all done in the backend).
But WebpackCopyPlugin copies it to look like this:
var is_admin=!1,is_user=!1,is_debug=!1,username="{{request.remote_user}}";
Why is it doing that?
Can I tell it to just copy the file as is without modifying it?
Thanks!
Modify the default minimizer options.
webpack.config.js
{
optimization: {
minimize: true,
minimizer: [new TerserPlugin({
exclude: /static/,
})]
}
}

Is there a grunt plugin to append text to a string inside files?

I have a set of files that I want to minify (I already have a grunt task for that) but before minifying them I want to append .min at the end of all the require functions so that the files point to the minified version.
I want to replace this:
const myModule = require('./my-module');
with this:
const myModule = require('./my-module.min');
so that when I minify this files and add the .min.js to the module file it finds the correct file.
I found the plug-in grunt-replace but I can't find a way to append (not even matching a string and replacing it with the samestring plus the .min)
How do can I accomplish this?
Generally speaking, modifying code inside of a build pipeline is a bad practice.
I would recommend using a conditional import statement instead. So your code would be changed to something like:
if(is_production){
const myModule = require('./my-module');
} else {
const myModule = require('./my-module.min');
}
You can then add the is_production variable in a number of ways:
As an Environment Variable at Runtime.
Using the existing NODE_ENV variable.
In Gulp, by appending a simple is_production = true line to the beginning.

webpack2 dynamic style file require

I am working with webpack 2 and I want to include some style file that depends from different NODE_ENV.
I did something like this:
const stylesEntryName = process.env.SECOND_CLIENT ? "main_for_second_client" : "main";
const entryUrl = `assets/styles/${stylesEntryName}.styl`;
console.log("stylesEntryName ====>>> ", stylesEntryName, entryUrl);
require(entryUrl);
But it isn't working somehow. I have got an error: Critical dependency: the request of a dependency is an expression
the console shows: stylesEntryName ====>>> main assets/styles/main.styl
Maybe I do something wrong? (in case of direct url)
require('assets/styles/main.styl');
the code working fine.
Thanks for any help.
webpack is emitting that warning about the line require(entryUrl) because the value of the entryUrl variable is unknown until the code is executed (i.e., the require is not statically analyzable). Here's the webpack documentation about that: https://webpack.github.io/docs/context.html#critical-dependencies
You can fix this problem by removing the dynamic require, and instead use if-else statements to pick a static require statement out of the possible choices. Here's code that does that for your issue:
if (process.env.SECOND_CLIENT === 'main_for_second_client') {
require('assets/styles/main_for_second_client.styl')
} else {
require('assets/styles/main.styl')
}

How can I exclude code path when bundling with webpack/browserify?

I have a library that can be used with both node.js and the browser. I am using CommonJS then publishing for the web version using webpack. My code looks like this:
// For browsers use XHR adapter
if (typeof window !== 'undefined') {
// This adapter uses browser's XMLHttpRequest
require('./adapters/xhr');
}
// For node use HTTP adapter
else if (typeof process !== 'undefined') {
// This adapter uses node's `http`
require('./adapters/http');
}
The problem I am encountering is that when I run webpack (browserify would do the same) the generated output includes http along with all it's dependencies. This results in a HUGE file which is not optimal for browser performance.
My question is how can I exclude the node code path when running a module bundler? I solved this temporarily by using webpack's externals and just returning undefined when including './adapters/http'. This doesn't solve the use case where other developers depend on my library using CommonJS. Their build will end up with the same problem unless they use similar exclude config.
I've looked at using envify, just wondering if there is another/better solution.
Thanks!
You may use IgnorePlugin for Webpack. If you are using a webpack.config.js file, use it like this:
var webpack = require('webpack')
var ignore = new webpack.IgnorePlugin(/^(canvas|mongoose|react)$/)
module.exports = {
//other options goes here
plugins: [ignore]
}
To push it further, you may use some flags like process.env.NODE_ENV to control the regex filter of IgnorePlugin
In order to exclude node_modules and native node libraries from being bundled, you need to:
Add target: 'node' to your webpack.config.js. This will exclude native node modules (path, fs, etc.) from being bundled.
Use webpack-node-externals in order to exclude all other node_modules.
So your result config file should look like:
var nodeExternals = require('webpack-node-externals');
...
module.exports = {
...
target: 'node', // in order to ignore built-in modules like path, fs, etc.
externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
...
};
This worked best for me
var _process;
try {
_process = eval("process"); // avoid browserify shim
} catch (e) {}
var isNode = typeof _process==="object" && _process.toString()==="[object process]";
as Node will return true and not only will the browser return false, but browserify will not include its process shim when compiling your code. As a result, your browserified code will be smaller.
Edit: I wrote a package to handle this more cleanly: broquire
You can use require.ensure for bundle splitting. For example
if (typeof window !== 'undefined') {
console.log("Loading browser XMLHttpRequest");
require.ensure([], function(require){
// require.ensure creates a bundle split-point
require('./adapters/xhr');
});
} else if (typeof process !== 'undefined') {
console.log("Loading node http");
require.ensure([], function(require){
// require.ensure creates a bundle split-point
require('./adapters/http');
});
}
See code splitting for more information and a sample demo usage here

How can I have webpack skip a module if it doesn't exist

I'm trying to use WebPack to include "showdown". The problem is that showdown will require("fs") and check the return value. This makes WebPack throw an error.
It seems like it should be possible to configure Webpack to generate a shim so that call to require("fs") will return false.
Maybe one of these techniques might work: http://webpack.github.io/docs/shimming-modules.html
Here's the Showdown.js code. If I comment out this code inside the node modules directory, the problem is solved. However, there should be a better way.
//
// Automatic Extension Loading (node only):
//
if (typeof module !== 'undefind' && typeof exports !== 'undefined' && typeof require !== 'undefind') {
var fs = require('fs');
if (fs) {
// Search extensions folder
var extensions = fs.readdirSync((__dirname || '.')+'/extensions').filter(function(file){
return ~file.indexOf('.js');
}).map(function(file){
return file.replace(/\.js$/, '');
});
// Load extensions into Showdown namespace
Showdown.forEach(extensions, function(ext){
var name = stdExtName(ext);
Showdown.extensions[name] = require('./extensions/' + ext);
});
}
}
The solution was to switch to marked: https://www.npmjs.org/package/marked. The showdown library is problematic as far as modules go.
Add it to noParse e.g.
var config = {
output: {
path: buildPath,
filename: 'bundle.js'
},
module: {
noParse: [
/showdown/,
],
And webpack will assume it does not contain any useful calls to require 🌹
This issue should be fixed in showdown v >=1.0.0
This seems to be a Showdown problem rather than a webpack one. The code that requires fs is intended to only be run in a node environment. Unfortunately there are some typos in the code that checks if it's running in node (the first if statement in the code you posted, undefind instead of undefined).
There is an pull request that fixes this which hasn't been merged yet.
To be honest it looks like the Showdown library is no longer maintained (last commit November 2012) so you may be better off looking for an alternative if possible.

Categories

Resources