Build JS from SJSIR `manually` - javascript

I need to build a js file from sjsir files at runtime to implement a system of plugins, so that it can't be done at compile time with the rest of my compilation. I used to implement the same process in 0.6.3 with the following code, but it seems to be deprecated. What algorithm do you recommand to achieve the same action with 0.6.13 ?
Thanks
val scalajsLib = copyJar("scalajs-library_2.11-0.6.3")
val semantics = org.scalajs.core.tools.sem.Semantics.Defaults
val partialClasspath =
PartialClasspathBuilder.build(collection.immutable.Seq(scalajsLib, src))
val completeClasspath = partialClasspath.resolve()
val optimizer = new ScalaJSOptimizer(semantics)
val logger = new ScalaConsoleLogger
val out = WritableFileVirtualJSFile(
new java.io.File(target, JS_FILE))
if (optimized) {
val sems = semantics.optimized
new ScalaJSClosureOptimizer(sems).optimizeCP(
new ScalaJSOptimizer(sems),
completeClasspath,
ScalaJSClosureOptimizer.Config(out),
logger
)
} else {
optimizer.optimizeCP(
completeClasspath,
ScalaJSOptimizer.Config(out, checkIR = false, wantSourceMap = !optimized),
logger
)
}

The Tools API has dramatically changed in 0.6.5, indeed. It became much simpler and more able to evolve in non-breaking ways in the future.
Your code above can be written with the new API as follows:
import java.io.File
import org.scalajs.core.tools.io._
import org.scalajs.core.tools.sem._
import org.scalajs.core.tools.linker.backend.{OutputMode, ModuleKind}
import org.scalajs.core.tools.linker.Linker
import org.scalajs.core.tools.logging.ScalaConsoleLogger
def link(inputClasspath: Seq[File], outputJSFile: File): Unit = {
// Obtain VirtualScalaJSIRFile's from the input classpath
val irCache = new IRFileCache().newCache
val irContainers = IRFileCache.IRContainer.fromClasspath(inputClasspath)
val sjsirFiles = irCache.cached(irContainers)
// A bunch of options. Here we use all the defaults
val semantics = Semantics.Defaults
val outputMode = OutputMode.Default
val moduleKind = ModuleKind.NoModule
val linkerConfig = Linker.Config()
// Actual linking
val linker = Linker(semantics, outputMode, moduleKind, linkerConfig)
val logger = new ScalaConsoleLogger
linker.link(sjsirFiles, WritableFileVirtualJSFile(outputJSFile), logger)
}
And you can call that link function with the following arguments, to exactly match your above snippet:
link(Seq(scalajsLib, src), new java.io.File(target, JS_FILE))
If you intend to call this method several times on the same classpath within the same process, it is advised to cache and reuse the instances irCache and linker across runs, as this will considerably speed up the process.
See also the Scaladoc of the Tools API.

Is there a way to prevent from errors about class repetition in the batch of sjsir (which generates the message: XXX already seen) at link time ? I guess it is, since this error does not occur when the build is done at compile time from the build.sbt.

Related

Functioning code no longer working after being minified and deployed

I have some code in a web worker that is working perfectly locally, but as soon as I build and deploy (which minifies the code) it no longer works.
The unminified code looks like this:
const mapSourceCode = (treeNode, mfi, {objectType, types, fileType, templateType}) => {
let sourceCodeMap = new Map();
let ownerMap = new Map();
let sourceCodeList = [];
let ownerList = [];
let mfiMap = new Map();
mfi.forEach(row => mfiMap.set(row.uuid, row));
let sourceCodeObjects = mfi.filter(row => types.includes(row.objectTypeUuid));
if(sourceCodeObjects.length < 1)
return {sourceCodeMap, sourceCodeTree: undefined};
try {
sourceCodeObjects.forEach(sourceObj => {
let owner = findOwner(sourceObj, sourceObj, mfiMap, {...treeNode.data}, objectType);
The minified code is this:
i = function(e, t, n) {
var c = n.objectType
, o = n.types
, i = n.fileType
, u = n.templateType
, l = new Map
, s = new Map
, f = []
, p = []
, m = new Map;
t.forEach((function(e) {
return m.set(e.uuid, e)
}
));
var h = t.filter((function(e) {
return o.includes(e.objectTypeUuid)
}
));
if (h.length < 1)
return {
sourceCodeMap: l,
sourceCodeTree: void 0
};
try {
if (h.forEach((function(n) {
var r = a(n, n, m, Object(d.a)({}, e.data), c);
The line it's erroring out on is {...treeNode.data} on the last line.
The error is ReferenceError: d is not defined
I can't figure out what the issue could be? Like I said everything runs great on locally. Any help is greatly appreciated
I found the issue, in case anybody runs into this same thing.
Normally when using web workers you need to tell your builder (webpack) to build / compile workers separately. I'm using the default create-react-app configuration which doesn't give access to that part of webpack. unless you eject from create-react-app completely (which I'm currently not ready to do)
I'm using the react hook called useWorker, where I pass the function I want to allocate to the worker.
When your code is optimized and minified variable names are replaced with smaller names (mostly 1 or 2 letters from what I've seen). Because I didn't have any custom loaders to load my worker code, it used variables from the global scope assuming it would have access. When the code was extracted to a separate thread outside the main thread it no longer had access to those variables and thus didn't work.
The fix is to
Add a loader (you can either eject from create-react-app, or there may be some npm libraries that will give you access to that particular part of webpack)
Or my solution was to create the function in a string and create a function using the Function constructor like so
const generateFunction = new Function('treeNode', 'mfi', 'types', 'action', generateFunctionString);
Where the generateFunctionString was a string like: "return a + b"
I then passed that function into my useWorker hook:
const [generatorWorker] = useWorker(generateFunction);

How to fix 'exports/require is not defined' from bundle.js after RXJS6 update in Angular 7 app

Recently I was updating Angular 5.1 ASP.NET application with RXJS 5 to latest Angular 7.2 with RXJS 6.3 With all this I also updated typescript from 2.8 to 3.2
At the end everything worked as expected, until I tried to run applicaiton using bundles on production. I was geting an error: 'ReferenceError: exports is not defined'
I tried to solve this error with simply defining exports to script tag:
<script> var exports = {}; </script>
which seems like an ughly hack but it did the job.
After that I got another error:
'ReferenceError: require is not defined'
I started to dig deeper and I found out that bundle.js contains something that looks like uncompiled code
new bundle.js contains this:
function nO(n, l) {
return n(l = {
exports: {}
}, l.exports), l.exports
}
Object.defineProperty(exports, "__esModule", {
value: !0
});
var lO = require("rxjs");
exports.Observable = lO.Observable, exports.Subject = lO.Subject;
var eO = require("rxjs/internal-compatibility");
exports.AnonymousSubject = eO.AnonymousSubject;
var tO = require("rxjs/internal-compatibility");
exports.config = tO.config, require("./add/observable/bindCallback"), require("./add/observable/bindNodeCallback"), require("./add/observable/combineLatest"), require("./add/observable/concat"), require("./add/observable/defer"), require("./add/observable/empty"), require("./add/observable/forkJoin"), require("./add/observable/from"), require("./add/observable/fromEvent"), require("./add/observable/fromEventPattern"), require("./add/observable/fromPromise"), require("./add/observable/generate"), require("./add/observable/if"), require("./add/observable/interval"), require("./add/observable/merge"), require("./add/observable/race"), require("./add/observable/never"), require("./add/observable/of"), require("./add/observable/onErrorResumeNext"), require("./add/observable/pairs"), require("./add/observable/range"), require("./add/observable/using"), require("./add/observable/throw"), require("./add/observable/timer"), require("./add/observable/zip"), require("./add/observable/dom/ajax"), require("./add/observable/dom/webSocket"), require("./add/operator/buffer"), require("./add/operator/bufferCount"), require("./add/operator/bufferTime"), require("./add/operator/bufferToggle"), require("./add/operator/bufferWhen"), require("./add/operator/catch"), require("./add/operator/combineAll"), require("./add/operator/combineLatest"), require("./add/operator/concat"), require("./add/operator/concatAll"), require("./add/operator/concatMap"), require("./add/operator/concatMapTo"), require("./add/operator/count"), require("./add/operator/dematerialize"), require("./add/operator/debounce"), require("./add/operator/debounceTime"), require("./add/operator/defaultIfEmpty"), require("./add/operator/delay"), require("./add/operator/delayWhen"), require("./add/operator/distinct"), require("./add/operator/distinctUntilChanged"), require("./add/operator/distinctUntilKeyChanged"), require("./add/operator/do"), require("./add/operator/exhaust"), require("./add/operator/exhaustMap"), require("./add/operator/expand"), require("./add/operator/elementAt"), require("./add/operator/filter"), require("./add/operator/finally"), require("./add/operator/find"), require("./add/operator/findIndex"), require("./add/operator/first"), require("./add/operator/groupBy"), require("./add/operator/ignoreElements"), require("./add/operator/isEmpty"), require("./add/operator/audit"), require("./add/operator/auditTime"), require("./add/operator/last"), require("./add/operator/let"), require("./add/operator/every"), require("./add/operator/map"), require("./add/operator/mapTo"), require("./add/operator/materialize"), require("./add/operator/max"), require("./add/operator/merge"), require("./add/operator/mergeAll"), require("./add/operator/mergeMap"), require("./add/operator/mergeMapTo"), require("./add/operator/mergeScan"), require("./add/operator/min"), require("./add/operator/multicast"), require("./add/operator/observeOn"), require("./add/operator/onErrorResumeNext"), require("./add/operator/pairwise"), require("./add/operator/partition"), require("./add/operator/pluck"), require("./add/operator/publish"), require("./add/operator/publishBehavior"), require("./add/operator/publishReplay"), require("./add/operator/publishLast"), require("./add/operator/race"), require("./add/operator/reduce"), require("./add/operator/repeat"), require("./add/operator/repeatWhen"), require("./add/operator/retry"), require("./add/operator/retryWhen"), require("./add/operator/sample"), require("./add/operator/sampleTime"), require("./add/operator/scan"), require("./add/operator/sequenceEqual"), require("./add/operator/share"), require("./add/operator/shareReplay"), require("./add/operator/single"), require("./add/operator/skip"), require("./add/operator/skipLast"), require("./add/operator/skipUntil"), require("./add/operator/skipWhile"), require("./add/operator/startWith"), require("./add/operator/subscribeOn"), require("./add/operator/switch"), require("./add/operator/switchMap"), require("./add/operator/switchMapTo"), require("./add/operator/take"), require("./add/operator/takeLast"), require("./add/operator/takeUntil"), require("./add/operator/takeWhile"), require("./add/operator/throttle"), require("./add/operator/throttleTime"), require("./add/operator/timeInterval"), require("./add/operator/timeout"), require("./add/operator/timeoutWith"), require("./add/operator/timestamp"), require("./add/operator/toArray"), require("./add/operator/toPromise"), require("./add/operator/window"), require("./add/operator/windowCount"), require("./add/operator/windowTime"), require("./add/operator/windowToggle"), require("./add/operator/windowWhen"), require("./add/operator/withLatestFrom"), require("./add/operator/zip"), require("./add/operator/zipAll");
var iO = require("rxjs");
exports.Subscription = iO.Subscription, exports.ReplaySubject = iO.ReplaySubject, exports.BehaviorSubject = iO.BehaviorSubject, exports.Notification = iO.Notification, exports.EmptyError = iO.EmptyError, exports.ArgumentOutOfRangeError = iO.ArgumentOutOfRangeError, exports.ObjectUnsubscribedError = iO.ObjectUnsubscribedError, exports.UnsubscriptionError = iO.UnsubscriptionError, exports.pipe = iO.pipe;
var uO = require("rxjs/testing");
exports.TestScheduler = uO.TestScheduler;
var oO = require("rxjs");
exports.Subscriber = oO.Subscriber, exports.AsyncSubject = oO.AsyncSubject, exports.ConnectableObservable = oO.ConnectableObservable, exports.TimeoutError = oO.TimeoutError, exports.VirtualTimeScheduler = oO.VirtualTimeScheduler;
var rO = require("rxjs/ajax");
exports.AjaxResponse = rO.AjaxResponse, exports.AjaxError = rO.AjaxError, exports.AjaxTimeoutError = rO.AjaxTimeoutError;
var sO = require("rxjs"),
aO = require("rxjs/internal-compatibility"),
cO = require("rxjs/internal-compatibility");
exports.TimeInterval = cO.TimeInterval, exports.Timestamp = cO.Timestamp;
var dO = require("rxjs/operators");
exports.operators = dO;
var pO = {
asap: sO.asapScheduler,
queue: sO.queueScheduler,
animationFrame: sO.animationFrameScheduler,
async: sO.asyncScheduler
};
Base on that I realized something is wrong with compiling rxjs to my bundle.js
Before update to latest version of angular, rxjs and typescript there was no mention of "rxjs" or any "require" statement in bundle.js.
So I first guessed this may be something new with RXJS6 or I forgot to do something somewhere.
I didn't do any drastic changes to tsconfig.js and I folowed all the update steps correctly.
Again, localy, using unbounded code everything works like a charm.
I wasn't able to find issue similar enough to learn from it or any mention of this behavior after update RXJS or typescript
I want to understand what happened here, why are there suddenly a lot of require statements in my bundle, and how to fix this issue.
I would like to avoid implementing RequireJS if this isn't necessary. I guess app should work without it
Thanks a lot for any help
There was quite a lot of changes between angular 5 and 7.
and also between rxjs 5 and 6.
You need to do quite a lot of steps to convert your codebase.
Fortunately angular has a good guide on how to do this.
https://update.angular.io
Make special note of the rxjs converter that converts between 5 and 6
npm install -g rxjs-tslint
rxjs-5-to-6-migrate -p src/tsconfig.app.json

NodeJS : Value for shared state of module

I am going through the tutorials of nodejs and while learning about the shared state of module, i come through few doubts :
i have written this code :
Sparsh.js
var popcorn = require('./popcorn');
popcorn.favPopCorn = 'cheese';
console.log(popcorn.favPopCorn);
Ravi.js
var popcorn = require('./popcorn');
console.log(popcorn.favPopCorn);
app.js
require('./Ravi');
require('./Sparsh');
require('./Ravi');
popcorn.js
module.exports = {
printRate : function() {
console.log('popcorn rate');
},
favPopCorn : ''
};
output
(blank)
cheese
(blank)
As per the output the firstblank is considerable as we didn't assign any value to favPopCorn.But after i assign the value to favPopCorn in Sparsh.js.It should print 'cheese' while we again use require('.\Ravi.js'); as it is a shared state.
Please help
Ravi.js is also shared (well, "cached" is a better word), so it's loaded just once (the first time). The second time, Node knows that it was already loaded and doesn't load (/execute) it a second time (it doesn't output a blank, it doesn't output at all).
A common method to work around that is to export a function:
// Ravi.js
var popcorn = require('./popcorn');
module.exports = function() {
console.log(popcorn.favPopCorn);
}
// Sparsh.js
var popcorn = require('./popcorn');
module.exports = function() {
popcorn.favPopCorn = 'cheese';
console.log(popcorn.favPopCorn);
}
// app.js
require('./Ravi')();
require('./Sparsh')();
require('./Ravi')();
A clean pattern for this kind of think is to create an object with new in your shared module:
//popcorn.js
function popcorn(){
this.printRate = function() {
console.log('popcorn rate');
}
this.favPopCorn = ""
}
module.exports = new popcorn()
Now when you get and set the favPopCorn property in other modules, you will be manipulating a singleton.

flatbuffers is not defined

I'm writing a nodeJs application that uses google flat buffer.
I installed flatc on my macbook pro and compiled the following schema:
namespace MyAlcoholist;
table Drink {
drink_type_name: string;
drink_company_name: string;
drink_brand_name: string;
drink_flavor_type_name : string;
liquid_color_type_name : string;
liquid_color_is_transparent : bool;
alcohol_vol : float;
calories_for_100g : uint;
global_image_id: ulong;
drink_flavor_id: ulong;
}
table Drinks { drinks:[Drink]; }
root_type Drinks;
the schema file is called drink.fbs and it generated a javascript file called drink_generated.js
I include this file in my nodejs application and add data to it using the following code.. this is my flatBufferUtil.js utility file.
var flatbuffers = require('../js/flatbuffers').flatbuffers;
var builder = new flatbuffers.Builder();
var drinks = require('../fbs/drinks_generated').MyAlcoholist; // Generated by `flatc`.
function drinkArrayToBuffer(drinkArray) {
var drinksVectArray = [];
drinkArray.forEach(function (element, index, array) {
var drinkObj = element;
var drinkBrandName = builder.createString(drinkObj.drink_brand_name);
var drinkCompanyName = builder.createString(drinkObj.drink_company_name);
var drinkflavorTypeName = builder.createString(drinkObj.drink_flavor_type_name);
var drinkTypeName = builder.createString(drinkObj.drink_type_name);
var liquidColorTypeName = builder.createString(drinkObj.liquid_color_type_name);
drinks.Drink.startDrink(builder);
drinks.Drink.addAlcoholVol(builder, drinkObj.alcohol_vol);
drinks.Drink.addCaloriesFor100g(builder,drinkObj.calories_for_100g);
drinks.Drink.addDrinkBrandName(builder,drinkBrandName);
drinks.Drink.addDrinkCompanyName(builder,drinkCompanyName);
drinks.Drink.addDrinkFlavorId(builder,drinkObj.drink_flavor_id);
drinks.Drink.addDrinkFlavorTypeName(builder, drinkflavorTypeName);
drinks.Drink.addDrinkTypeName(builder,drinkTypeName);
drinks.Drink.addGlobalImageId(builder,drinkObj.global_image_id);
drinks.Drink.addLiquidColorIsTransparent(builder,drinkObj.is_transparent);
drinks.Drink.addLiquidColorTypeName(builder,liquidColorTypeName);
var drink = drinks.Drink.endDrink(builder);
drinksVectArray.push(drink);
})
var drinksVect = drinks.createDrinksVector(builder,drinksVectArray);
builder.finish(drinksVect);
var buf = builder.dataBuffer();
return buf;
}
module.exports.drinkArrayToBuffer=drinkArrayToBuffer;
now when I execute this function it fails with the error flatbuffers is not defined.
I debugged my code and I saw that it files on the following line of code:
drinks.Drink.addDrinkFlavorId(builder,drinkObj.drink_flavor_id);
if i get inside addDrinkFlavorId function i see this code in drinks_generted.js:
MyAlcoholist.Drink.addDrinkFlavorId = function(builder, drinkFlavorId) {
builder.addFieldInt64(9, drinkFlavorId, flatbuffers.Long.ZERO);
};
as you can see it uses flatbuffers.Long.ZERO but flatbuffers is not defined in that file at all. the compilation did not provide any errors so what do I miss?
It seems to me like it is a bug... The generated file appears to be meant to exist autonomously from the flatbuffers require. However for the custom flatbuffers.Long class, the default of flatbuffers.Long.ZERO bleeds into the generated file.
While this isn't a solution per-say, one workaround is to manually add the flatbuffers require to the generated file; it's ugly, but it might be better than being blocked until a more appropriate answer (or fix) comes around.
// In `drinks_generated.js`
var flatbuffers = require('../js/flatbuffers').flatbuffers;
Note:
The drinks.Drink.addDrinkFlavorId() and drinks.Drink.addGlobalImageId() functions expect flatbuffers.Long values to be passed into them, because they were specified as ulong in the schema (fbs file). So you will need to ensure that you are not trying to pass in a simple number type.
For example:
var my_long = flatbuffers.Long(100, 0); // low = 100, high = 0
drinks.Drink.addDrinkFlavorId(builder, my_long);
As a result, another possible workaround is to change the datatype of those fields in the schema to avoid using ulong until it becomes more clear what is going on here.
P.S. I am pretty sure drinks.createDrinksVector on line 30 of that snippet should be drinks.Drinks.createDrinksVector.

How do I require() from the console using webpack?

How do I require() / import modules from the console? For example, say I've installed the ImmutableJS npm, I'd like to be able to use functions from the module while I'm working in the console.
Here's another more generic way of doing this.
Requiring a module by ID
The current version of WebPack exposes webpackJsonp(...), which can be used to require a module by ID:
function _requireById(id) {
return webpackJsonp([], null, [id]);
}
or in TypeScript
window['_requireById'] =
(id: number): any => window['webpackJsonp'];([], null, [id]);
The ID is visible at the top of the module in the bundled file or in the footer of the original source file served via source maps.
Requiring a module by name
Requiring a module by name is much trickier, as WebPack doesn't appear to keep any reference to the module path once it has processed all the sources. But the following code seems to do the trick in lot of the cases:
/**
* Returns a promise that resolves to the result of a case-sensitive search
* for a module or one of its exports. `makeGlobal` can be set to true
* or to the name of the window property it should be saved as.
* Example usage:
* _requireByName('jQuery', '$');
* _requireByName('Observable', true)ยด;
*/
window['_requireByName'] =
(name: string, makeGlobal?: (string|boolean)): Promise<any> =>
getAllModules()
.then((modules) => {
let returnMember;
let module = _.find<any, any>(modules, (module) => {
if (_.isObject(module.exports) && name in module.exports) {
returnMember = true;
return true;
} else if (_.isFunction(module.exports) &&
module.exports.name === name) {
return true;
}
});
if (module) {
module = returnMember ? module.exports[name] : module.exports;
if (makeGlobal) {
const moduleName = makeGlobal === true ? name : makeGlobal as string;
window[moduleName] = module;
console.log(`Module or module export saved as 'window.${moduleName}':`,
module);
} else {
console.log(`Module or module export 'name' found:`, module);
}
return module;
}
console.warn(`Module or module export '${name}'' could not be found`);
return null;
});
// Returns promise that resolves to all installed modules
function getAllModules() {
return new Promise((resolve) => {
const id = _.uniqueId('fakeModule_');
window['webpackJsonp'](
[],
{[id]: function(module, exports, __webpack_require__) {
resolve(__webpack_require__.c);
}},
[id]
);
});
}
This is quick first shot at this, so it's all up for improvement!
Including this in a module will allow require([modules], function) to be used from a browser
window['require'] = function(modules, callback) {
var modulesToRequire = modules.forEach(function(module) {
switch(module) {
case 'immutable': return require('immutable');
case 'jquery': return require('jquery');
}
})
callback.apply(this, modulesToRequire);
}
Example Usage:
require(['jquery', 'immutable'], function($, immutable) {
// immutable and $ are defined here
});
Note: Each switch-statement option should either be something this module already requires, or provided by ProvidePlugin
Sources:
Based on this answer, which can be used to add an entire folder.
Alternative method from Webpack Docs - which allows something like require.yourModule.function()
I found a way that works, for both WebPack 1 and 2. (as long as the source is non-minified)
Repo: https://github.com/Venryx/webpack-runtime-require
Install
npm install --save webpack-runtime-require
Usage
First, require the module at least once.
import "webpack-runtime-require";
It will then add a Require() function to the window object, for use in the console, or anywhere in your code.
Then just use it, like so:
let React = Require("react");
console.log("Retrieved React.Component: " + React.Component);
It's not very pretty (it uses regexes to search the module wrapper functions) or fast (takes ~50ms the first call, and ~0ms after), but both of these are perfectly fine if it's just for hack-testing in the console.
Technique
The below is a trimmed version of the source to show how it works. (see the repo for the full/latest)
var WebpackData;
webpackJsonp([],
{123456: function(module, exports, __webpack_require__) {
WebpackData = __webpack_require__;
}},
[123456]
);
var allModulesText;
var moduleIDs = {};
function GetIDForModule(name) {
if (allModulesText == null) {
let moduleWrapperFuncs = Object.keys(WebpackData.m).map(moduleID=>WebpackData.m[moduleID]);
allModulesText = moduleWrapperFuncs.map(a=>a.toString()).join("\n\n\n");
// these are examples of before and after webpack's transformation: (which the regex below finds the var-name of)
// require("react-redux-firebase") => var _reactReduxFirebase = __webpack_require__(100);
// require("./Source/MyComponent") => var _MyComponent = __webpack_require__(200);
let regex = /var ([a-zA-Z_]+) = __webpack_require__\(([0-9]+)\)/g;
let matches = [];
let match;
while (match = regex.exec(allModulesText))
matches.push(match);
for (let [_, varName, id] of matches) {
// these are examples of before and after the below regex's transformation:
// _reactReduxFirebase => react-redux-firebase
// _MyComponent => my-component
// _MyComponent_New => my-component-new
// _JSONHelper => json-helper
let moduleName = varName
.replace(/^_/g, "") // remove starting "_"
.replace(new RegExp( // convert chars where:
"([^_])" // is preceded by a non-underscore char
+ "[A-Z]" // is a capital-letter
+ "([^A-Z_])", // is followed by a non-capital-letter, non-underscore char
"g"),
str=>str[0] + "-" + str[1] + str[2] // to: "-" + char
)
.replace(/_/g, "-") // convert all "_" to "-"
.toLowerCase(); // convert all letters to lowercase
moduleIDs[moduleName] = parseInt(id);
}
}
return moduleIDs[name];
}
function Require(name) {
let id = GetIDForModule(name);
return WebpackData.c[id].exports;
}
Being able to use require modules in the console is handy for debugging and code analysis. #psimyn's answer is very specific so you aren't likely to maintain that function with all the modules you might need.
When I need one of my own modules for this purpose, I assign a window property to it so I can get at it e.g window.mymodule = whatever_im_exporting;. I use the same trick to expose a system module if I want to play with it e.g:
myservice.js:
let $ = require('jquery');
let myService = {};
// local functions service props etc...
module.exports = myService;
// todo: remove these window prop assignments when done playing in console
window.$ = $;
window.myService = myService;
It is still a bit of a pain, but digging into the bundles, I can't see any way to conveniently map over modules.
The answer from #Rene Hamburger is good but unfortunately doesn't work anymore (at least with my webpack version). So I updated it:
function getWebpackInternals() {
return new Promise((resolve) => {
const id = 'fakeId' + Math.random();
window['webpackJsonp'].push(["web", {
[id]: function(module, __webpack_exports__, __webpack_require__) {
resolve([module, __webpack_exports__, __webpack_require__])
}
},[[id]]]);
});
}
function getModuleByExportName(moduleName) {
return getWebpackInternals().then(([_, __webpack_exports__, __webpack_require__]) => {
const modules = __webpack_require__.c;
const moduleFound = Object.values(modules).find(module => {
if (module && module.exports && module.exports[moduleName]) return true;
});
if (!moduleFound) {
console.log('couldnt find module ' + moduleName);
return;
}
return moduleFound.exports[moduleName];
})
}
getModuleByExportName('ExportedClassOfModule');
expose-loader is, in my opinion, a more elegant solution:
require("expose-loader?libraryName!./file.js");
// Exposes the exports for file.js to the global context on property "libraryName".
// In web browsers, window.libraryName is then available.
Adding the below code to one of your modules will allow you to load modules by id.
window.require = __webpack_require__;
In the console use the following:
require(34)
You could do something similar as psimyn advised by
adding following code to some module in bundle:
require.ensure([], function () {
window.require = function (module) {
return require(module);
};
});
Use require from console:
require("./app").doSomething();
See more
After making an npm module for this (see my other answer), I did a search on npms.io and seem to have found an existing webpack-plugin available for this purpose.
Repo: https://www.npmjs.com/package/webpack-expose-require-plugin
Install
npm install --save webpack-expose-require-plugin
Usage
Add the plugin to your webpack config, then use at runtime like so:
let MyComponent = require.main("./path/to/MyComponent");
console.log("Retrieved MyComponent: " + MyComponent);
See package/repo readme page for more info.
EDIT
I tried the plugin out in my own project, but couldn't get it to work; I kept getting the error: Cannot read property 'resource' of undefined. I'll leave it here in case it works for other people, though. (I'm currently using the solution mentioned above instead)
After both making my own npm package for this (see here), as well as finding an existing one (see here), I also found a way to do it in one-line just using the built-in webpack functions.
It uses WebPack "contexts": https://webpack.github.io/docs/context.html
Just add the following line to a file directly in your "Source" folder:
window.Require = require.context("./", true, /\.js$/);
Now you can use it (eg. in the console) like so:
let MyComponent = Require("./Path/To/MyComponent");
console.log("Retrieved MyComponent: " + MyComponent);
However, one important drawback of this approach, as compared to the two solutions mentioned above, is that it seems to not work for files in the node_modules folder. When the path is adjusted to "../", webpack fails to compile -- at least in my project. (perhaps because the node_modules folder is just so massive)

Categories

Resources