Webpack creating duplicate entries for dependencies - javascript

I am trying to switch from using browserify to webpack. One thing browserify handled nicely was dependency management inside dependencies. Let me give an example:
Main app project:
var util1 = require('shared-components/util1');
var util2 = require('shared-components/util2');
Inside shared-components/util1.js
var util2 = require('../util2');
Browserify would realize that the reference to util2 in both scenarios was the same but it appears that Webpack does not which creates duplicate entries for util2.
Is there a configuration setting or plugin I can use to resolve this?

Try new webpack.optimize.DedupePlugin(). See the docs for more info.

Related

Obscurify react code in production by automatically changing all the function and variable names

Are there any libs that help obscurify a react build for production?
Something like:
const MyComp = () = > {
const {propa, propb} = useMyfunc()
return(...)
}
to
const xyz = () = > {
const {yxz, zyx} = zzz()
return(...)
}
Is this library what you are looking for?
Have you ever try this package?
this is a very professional package for obfuscate js codes which convert your code:
const MyComp = () = > {
const {propa, propb} = useMyfunc()
return(...)
}
to this:
const MyComp=()=>{const {propa:_0xa95d6e,propb:_0xfaabf6}=useMyfunc();return _0xa95d6e+_0xfaabf6;};
The right choice would be Terser. it is availble along with webpack too (terser-webpack-plugin) for ES6+.
uglify-es is no longer maintained and uglify-js does not support ES6+.
You can refer to benchmarks for different packages from this article.
UglifyJS has options to mangle (obscurify) names:
Sample input:
const MyComp = function() {
const {propa, propb} = useMyfunc()
return(1)
}
Sample output:
const n=function(){const{propa:n,propb:o}=useMyfunc();return 1};
Try it yourself: https://www.uglifyjs.net/
useMyfunc cannot be mangled unless the function definition is included (otherwise the function call would fail.) Similarly, mangling top-level globals like MyComp may break anything that uses that component.
If you bundle all your React code into a single file before mangling, it should work because all the references will be mangled to correctly matching names.
React already uses a minifier like UglifyJS, so you may be able to just modify some configuration files. Note source maps will undermine any mangling, so they should be disabled. (I think React is more interested in the smaller JS files than obscuring code.)
Complementing Ashwin R's response...
As pointed out, Terser is a good choice for doing it.
React uses some form of UglifyJS to minify your code on build, but in order to obfuscate variables and function names I did the following:
Instructions:
1° - Install Terser
npm install terser
2° - Modify package.json:
"terser": "terser ./build/static/js/*.js -c -m --mangle-props regex=/_$/",
"build": "react-scripts build && npm run terser"
That seems to have worked for me; hopefully it does for you as well!
react-obfuscate
There is one npm repository that takes care of react code obfuscation. Below is the link for the same -
https://www.npmjs.com/package/react-obfuscate
Basic steps are written in the repo documentation itself.
Jscrambler
Another tool that I find interesting is Jscrambler.
https://blog.jscrambler.com/protecting-your-react-js-source-code-with-jscrambler/

Application modularity with Vue.js and local NPM packages

I'm trying to build a modular application in Vue via the vue-cli-service. The main app and the modules are separated projects living in different folders, the structure is something like this:
-- app/package.json
/src/**
-- module1/package.json
/src**
-- module2/package.json
/src**
The idea is to have the Vue app completely agnostic about the application modules that can be there at runtime, the modules themself are compiled with vue-cli-service build --target lib in a local moduleX/dist folder, pointed with the package.json "main" and "files" nodes.
My first idea (now just for development speed purposes) was to add the modules as local NPM packages to the app, building them with a watcher and serving the app with a watcher itself, so that any change to the depending modules would (I think) be distributed automatically to the main app.
So the package.json of the app contains dependencies like:
...
"module1": "file:../module1",
"module2": "file:../module2",
...
This dependencies are mean to be removed at any time, or in general be composed as we need, the app sould just be recompiled and everything should work.
I'm trying to understand now how to dynamically load and activate the modules in the application, as I cannot use the dynamic import like this:
import(/* webpackMode: "eager" */ `module1`).then(src => {
src.default.boot();
resolve();
});
Because basically I don't know the 'module1', 'module2', etc...
In an OOP world I would just use dependency injection retrieving classes implementing a specific interface, but in JS/TS I'm not sure it is viable.
There's a way to accomplish this?
Juggling with package.json doesn't sound like a good idea to me - doesn't scale. What I would do:
Keep all available "modules" in package.json
Create separate js file (or own prop inside package.json) with all available configurations (for different clients for example)
module.exports = {
'default': ['module1', 'module2', 'module3'],
'clientA': ['module1', 'module2', 'module4'],
'clientB': ['module2', 'module3', 'module4']
}
tap into VueCLI build process - best example I found is here and create js file which will run before each build (or "serve") and using simple template (for example lodash) generate new js file which will boot configured modules based on the value of some ENV variable. See following (pseudo)code (remember this runs inside node during build):
const fs = require('fs')
const _ = require('lodash')
const modulesConfig = require(`your module config js`)
const configurationName = process.env.MY_APP_CONFIGURATION ?? 'default'
const modules = modulesConfig[configurationName]
const template = fs.loadFileSync('name of template file')
const templateCompiled = _.template(template)
const generatedJS = templateCompiled({ `modules`: modules })
fs.writeFileSync('bootModules.js', generatedJS)
Write your template for bootModules.js. Simplest would be:
<% _.forEach(modules , function(module) { %>import '<%= module %>' as <%= module %><% }); %>;
import bootModules.js into your app
Use MY_APP_CONFIGURATION ENV variable to switch desired module configuration - works not just during development but you can also setup different CI processes targeting same repo with just different MY_APP_CONFIGURATION values
This way you have all configurations at one place, you don't need to change package.json before every build, you have simple mechanism to switch between different module configurations and every build (bundle) contains only the modules needed....
In an OOP world I would just use dependency injection retrieving classes implementing a specific interface, but in JS/TS I'm not sure it is viable.
Why not?
More than this, with JS/TS you are not restricted to use classes implementing a specific interface: you just need to define the interface (i.e. the module.exports) of your modules and respecting it in the libraries entries (vue build lib).
EDIT: reading comments probably I understood the request.
Each module should respect following interface (in the file which is the entry of the vue library)
export function isMyAppModule() {
return true;
}
export function myAppInit() {
return { /* what you need to export */ };
}
Than in your app:
require("./package.json").dependencies.forEach(name => {
const module = require(name);
if(! module.isMyAppModule || module.isMyAppModule() !== true) return;
const { /* the refs you need */ } = module.myAppInit();
// use your refs as you need
});

Using Webpack to add JavaScript module to ASP.NET MVC app

I'm trying to use Webpack to create a couple of simple modules in an ASP.NET MVC 5 Visual Studio 2015 project. Following instructions on the Webpack site, I downloaded the latest version of Node.js. Then using the Node command prompt, changed to my project's folder. There, I ran this command to install Webpack locally:
npm install webpack --save-dev
It created a package.json file in the root of my project:
{
"devDependencies": {
"webpack": "^2.4.1"
}
}
Note that the project already has jQuery and Bootstrap as bundles via the BundleConfig.cs, which are then referenced on _Layout.cshtml; hence they're available on all pages of the app.
Now I'd like to create a very simple test to see how to create and require modules using Webpack; once I understand it better, I can add more complex modules. I've been reading about code-splitting: https://webpack.js.org/guides/code-splitting-async/ but it's still not clear how you do this.
The function test requires function isEmpty. I'd like to define isEmpty as a module and then use it with test.
var test = function(value){
return isEmpty(value);
};
var isEmpty = function(value) {
return $.trim(value).length === 0 ? true : false;
};
This article has been helping: http://developer.telerik.com/featured/webpack-for-visual-studio-developers/
The Webpack documentation mentions import() and also require.ensure(). How do I use Webpack to modularize the isEmpty code and then use it?
Webpack allows you to use the commonJS approach for dependency management which Node.js uses, so if you have experience with Node.js it's very similar.
If not have a look at this article on the module system or the spec for a description of the module system.
For this problem I will assume all files are in the same directory. I think you will need to first move the isEmpty code into a separate file maybe isEmpty.js and change it's structure a bit so that it looks like this:
module.exports = function(value) {
return $.trim(value).length === 0 ? true : false;
};
then your test function can be moved into a separate test.js file and you can require the isEmpty module and use it like this:
var isEmpty = require('./isEmpty');
var test = function(value){
return isEmpty(value);
};
You will probably have to do something about the dependency on $ (I'm guessing jquery?) but I think that can be handled with shimming
If you have a number of functions you can do something like:
someFunctions.js
var self = {};
self.Double = function(value){
return value*2;
}
self.Triple = function(value){
return value*3;
}
module.exports = self;
useFunctions.js
var useFunctions = require('./someFunctions');
var num = 5;
console.log(useFunctions.Double(num));
console.log(useFunctions.Triple(num));

Is it possible to require modules from outside of your project directory without relative paths?

I'm trying to build a local library of JS modules to use in Node projects.
If a new project lives in /Users/me/projects/path/to/new/project/ and my library files are located in /Users/me/projects/library/*.js is there a way to access those files without using a relative path?
In /Users/me/projects/path/to/new/project/app.js you can require foo.js like so:
var foo = require('../../../../../library/foo') and that will work but that's clunky and if files move you'd have to update your relative paths.
I've tried requireFrom and app-module-path with no luck as they are relative to a project root.
Any ideas for how to require files from outside of your project dir?
Thanks in advance!
var librarypath = '/Users/me/projects/library/';
// or if you prefer...
// var librarypath = '../../../../../library/';
var foo = require(librarypath + 'foo.js');
... or dressed up a bit more ...
function requirelib(lib){ return require('/Users/me/projects/library/'+lib+'.js'); }
var foo = requirelib('foo');
var bar = requirelib('bar');
I had the same problem many times. This can be solved by using the basetag npm package. It doesn't have to be required itself, only installed as it creates a symlink inside node_modules to your base path.
const localFile = require('$/local/file')
// instead of
const localFile = require('../../local/file')
Using the $/... prefix will always reference files relative to your apps root directory.
Disclaimer: I created basetag to solve this problem

Getting started with unit testing JavaScript without a framework

I am building a JavaScript application (no framework yet, but I may move it to Backbone). I have created various classes, here's an example, chart.js:
var moment = require('moment');
var chart = {
...
getAllMonths: function(firstMonth, lastMonth) {
var startDate = moment(firstMonth);
var endDate = moment(lastMonth);
var monthRange = [];
while (startDate.isBefore(endDate)) {
monthRange.push(startDate.format("YYYY-MM-01"));
startDate.add(1, 'month');
}
return monthRange;
},
setMonths: function() {
// get data via ajax
this.globalOptions.months = this.getAllMonths(data['firstMonth'], data['lastMonth']);
}
};
module.exports = chart;
My file structure is as follows:
index.js
src/
chart.js
form.js
I import the two classes into index.js and use browserify to bundle these scripts up in order to use them in my web app.
Now I want to add tests for chart.js and form.js. I have added a new directory called test/ and empty test files:
index.js
src/
chart.js
form.js
test/
test_chart.js
test_form.js
My question now is what test_chart.js should look like in order to test the getAllMonths function, and what test runner I should use.
I've started experimenting with the following in test_chart.js:
console.log('hello world');
var chart = require('../src/chart');
var months = chart.getAllMonths('2014-02-01', '2015-03-01');
// assert if months.length != 14
But if I run this with node test/test_chart.js, I get errors about failed module imports for moment etc (shouldn't these be imported automatically with the original chart.js module?).
Secondly, what test runner could I use for this kind of simple testing? I'd like something that will automatically run everything in the test directory, and offers asserts etc.
I ended up using Mocha. It's really pretty easy:
npm install --save-dev mocha
mocha
Boom!
It automatically looks for files in the test/ folder.
Still having the problem with imports though.

Categories

Resources