I'm getting a webpack error when trying to require an image file I know exists in my v-img component here:
imgSrcFancy (imgsize) {
try {
// if in production, unless no imgsize is specified, use .imgs instead of fullsize
// if (imgsize === '' || process.env.NODE_ENV === 'development') {
if (imgsize === '') { // temporarily force always use .imgs for testing only
console.log('fallback on full-rez load')
return require(`~/content${this.dirp}/${this.src}`)
} else { // production and imgsize not empty
const path = require('path')
const ext = path.extname(this.src)
const name = path.basename(this.src, ext)
const loadstring = `~/content${this.dirp}/.imgs/${name}_${imgsize}${ext}`
console.log('fancy load from ' + loadstring)
return require(`~/content${this.dirp}/.imgs/${name}_${imgsize}${ext}`)
}
} catch (error) {
console.log('error with finding image for: ' + this.src)
console.log(error)
return null
}
Background:
I have a blog that uses nuxt-content.
The project is organized so that images are grouped along with post .md files in a folder for each post inside /content/posts. My starting v-img component works fine, requiring these images no problem. (note this last link is to the master branch that is deployed, while the earlier is to a feature branch)
My deployed site is very slow to load, so I wrote a python program to generate smaller versions of the images, all stored in a .imgs folder within each slug folder as follows:
- content/
- posts/
- post-slug-one/
- index.md
- my_image1.jpg
...
- .imgs/
- my_image1_large.jpg
- my_image1_tn.jpg
...
The python program is invoked as part of my netlify build command, e.g. python3 ./gen_tn.py && nuxt build && nuxt generate. This works fine.
To avoid clogging up disk space locally, I'm using NODE_ENV to just use full sizes when in development; this works fine too, but I've temporarily disabled this to test.
I generated thumbnails locally for testing, but the problem comes when I hit the line:
return require(`~/content${this.dirp}/.imgs/${name}_${imgsize}${ext}`)
I get an exception:
Error: Cannot find module './content/posts/sept-2021-photos-things/.imgs/pos_DSC01274_large.jpg'
at webpackContextResolve (content.*$:752)
at webpackContext (content.*$:747)
at VueComponent.imgSrcFancy (VImg.vue:59)
at Proxy.render (VImg.vue?ad21:7)
at VueComponent.Vue._render (vue.runtime.esm.js:3548)
at VueComponent.updateComponent (vue.runtime.esm.js:4055)
at Watcher.get (vue.runtime.esm.js:4479)
at Watcher.run (vue.runtime.esm.js:4554)
at flushSchedulerQueue (vue.runtime.esm.js:4310)
at Array.<anonymous> (vue.runtime.esm.js:1980)
But this file exists:
MBPro:bst-blog$ ls content/posts/sept-2021-photos-things/.imgs/pos_DSC01274_large.jpg
content/posts/sept-2021-photos-things/.imgs/pos_DSC01274_large.jpg
I've tried even hard-coding the image size, but that doesn't work either:
return require(\`~/content${this.dirp}/.imgs/${name}_large${ext}`)
What am I doing wrong? How do I fix this? Any guidance appreciated!
Ok.
Turns out the problem was with the name I was using for the thumbnails - webpack did not like .imgs. Changing it to imgs (or gen_tn_imgs to make adding a specific rule to .gitignore easy, in my case).
My final block looks like this:
methods: {
imgSrcFancy (imgsize) {
try {
// if in production, unless no imgsize is specified, use .imgs instead of fullsize
if (imgsize === '' || imgsize === 'orig' || process.env.NODE_ENV === 'development') {
// if (imgsize === '') { // temporarily force always use .imgs for testing only
console.log('fallback on full-rez load')
return require(`~/content${this.dirp}/${this.src}`)
} else { // production and imgsize not empty
const path = require('path')
const ext = path.extname(this.src)
const name = path.basename(this.src, ext)
const loadstring = `~/content${this.dirp}/gen_tn_imgs/${name}_${imgsize}.png`
console.log('fancy load from ' + loadstring)
return require(`~/content${this.dirp}/gen_tn_imgs/${name}_${imgsize}.png`) // working
}
} catch (error) {
console.log('error with finding image for: ' + this.src)
console.log(error)
return null
}
}
}
and it's called like so:
<a :href="imgSrcFancy('orig')">
<img :src="imgSrcFancy('large')" :alt="alt">
</a>
An upcoming feature of the Windows Terminal preview is that it has full emoji support:
Compared to:
In Node.js, how do I detect if I'm running in a terminal wrapped by the Windows Terminal instead of its "naked" variation? Is there an environmental variable I can extract or a synchronous test I can do?
You can check for the WT_SESSION environmental variable which is set to a v4 UUID: https://github.com/microsoft/terminal/issues/1040
If you're looking for a quick and dirty way to check, this should work:
!!process.env.WT_SESSION
There's also a more elaborate method you can use, taking advantage of is-uuid, is-wsl and process.platform:
import isUUID from 'is-uuid';
import isWsl from 'is-wsl';
const isWindowsTerminal = (process.platform === "win32" || isWsl) && isUUID.v4(process.env.WT_SESSION);
I prefer this approach from https://github.com/microsoft/terminal/issues/6269 (in PowerShell):
function IsWindowsTerminal ($childProcess) {
if (!$childProcess) {
return $false
} elseif ($childProcess.ProcessName -eq 'WindowsTerminal') {
return $true
} else {
return IsWindowsTerminal -childProcess $childProcess.Parent
}
}
which I then use in my profile to turn on e.g. oh-my-posh.
$IsWindowsTerminal = IsWindowsTerminal -childProcess (Get-Process -Id $PID)
if($IsWindowsTerminal) {
oh-my-posh --init --shell pwsh --config $HOME\Documents\mytheme.omp.json | Invoke-Expression
}
Im trying to integrate Applozic chat platform to my Ionic 2 project, which I wish to export to Web, Android and iOS. Using the sample as a base and created the applozic.d.ts & applozichv.js for the Javascript integration process.
applozic.d.ts
interface AppLozicStatic {
initPlugin(): any;
}
declare var AppLozic : AppLozicStatic;
export = AppLozic;
applozichv.js
(function () {
var root = this;
var AppLozic = function (obj) {
if (obj instanceof AppLozic) return obj;
if (!(this instanceof AppLozic)) return new AppLozic(obj);
// this.EXIFwrapped = obj;
};
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = AppLozic;
}
exports.AppLozic = AppLozic;
} else {
root.AppLozic = AppLozic;
}
AppLozic.initPlugin = function () {
var $original;
// var $applozic = "";
var $applozic;
console.log("initPlugin");
$original = jQuery.noConflict(true);
$ = $original;
jQuery = $original;
if (typeof jQuery !== 'undefined') {
console.log("initPlugin 1");
$applozic = jQuery.noConflict(true);
$applozic.fn
.applozic({
baseUrl : 'https://apps.applozic.com',
userId : 'debug454545', //TODO: replace userId with actual UserId
userName : 'test', //TODO: replace userId with actual UserName
appId : 'applozic-sample-app',
// accessToken: 'suraj', //TODO: set user access token.for new user it will create new access token
ojq: $original,
// obsm: oModal,
//optional, leave it blank for testing purpose, read this if you want to add additional security by verifying password from your server https://www.applozic.com/docs/configuration.html#access-token-url
// authenticationTypeId: 1, //1 for password verification from Applozic server and 0 for access Token verification from your server
// autoTypeSearchEnabled : false,
// messageBubbleAvator: true,
notificationIconLink: "https://www.applozic.com/resources/images/applozic_icon.png",
notificationSoundLink: "",
readConversation: readMessage, // readMessage function defined above
onInit: onInitialize, //callback function execute on plugin initialize
maxAttachmentSize: 25, //max attachment size in MB
desktopNotification: true,
locShare: true,
video: true,
topicBox: true,
// mapStaticAPIkey: "AIzaSyCWRScTDtbt8tlXDr6hiceCsU83aS2UuZw",
// googleApiKey: "AIzaSyDKfWHzu9X7Z2hByeW4RRFJrD9SizOzZt4" // replace it with your Google API key
// initAutoSuggestions : initAutoSuggestions // function to enable auto suggestions
});
}
var oModal = "";
/*if (typeof $original !== 'undefined') {
$ = $original;
jQuery = $original;
if (typeof $.fn.modal === 'function') {
oModal = $.fn.modal.noConflict();
}
} else {
$ = $applozic;
jQuery = $applozic;
if (typeof $applozic.fn.modal === 'function') {
oModal = $applozic.fn.modal.noConflict();
}
}*/
//Sample json contains display name and photoLink for userId
function readMessage() {
//console.log(userId);
}
//callback function execute after plugin initialize.
function onInitialize(response, data) {
if (response.status === 'success') {
// $applozic.fn.applozic('loadContacts', {'contacts':contactsJSON});
// $applozic.fn.applozic('loadTab', 'shanki.connect');
//write your logic exectute after plugin initialize.
alert("success");
} else {
alert(response.errorMessage);
}
}
// init();
};
})();
I added all the above created files including applozic.common.js, applozic.fullview.js and jquery.min.js to the assets/js folder and linked them in my index.html. This was the only way I could get the JavaScript method in applozic.js to execute from my chat.ts.
The problem that i'm now facing is the I get the error:
TypeError: Cannot read property 'noConflict' of undefined` in `applozic.js`
on the line
$original = jQuery.noConflict(true);
and consequently the rest of the if block is also not executing.
In an attempt to make jQuery work in the project I tried to install it via NPM by executing the following commands:
npm install jquery --save
npm install #types/jquery --save
But this led to issue in ionic serve giving the following error:
JavaScript heap out of memory
I really need help in executing my applozic.js file to initialize and call the chat plugin functions.
You should first identify the actual problem.
If problem is in jquery installation, then you can debug it using following line.
console.log("Jwuery Text : " , $('.testClassName'));
If below log is completely printed in the console then there is no mistake in jquery.
This memory size issue is resolved using reInitialize memory heap by using this command :
set NODE_OPTIONS=--max_old_space_size=4096
or
node --max_old_space_size=4096
After this command run into the command prompt, try to serve project or build a project.
This is a bit of an edge case but it would be helpful to know.
When developing an extension using webpack-dev-server to keep the extension code up to date, it would be useful to listen to "webpackHotUpdate"
Chrome extensions with content scripts often have two sides to the equation:
Background
Injected Content Script
When using webpack-dev-server with HMR the background page stays in sync just fine. However content scripts require a reload of the extension in order to reflect the changes. I can remedy this by listening to the "webpackHotUpdate" event from the hotEmmiter and then requesting a reload. At present I have this working in a terrible and very unreliably hacky way.
var hotEmitter = __webpack_require__(XX)
hotEmitter.on('webpackHotUpdate', function() {
console.log('Reloading Extension')
chrome.runtime.reload()
})
XX simply represents the number that is currently assigned to the emitter. As you can imagine this changed whenever the build changes so it's a very temporary proof of concept sort of thing.
I suppose I could set up my own socket but that seems like overkill, given the events are already being transferred and I simply want to listen.
I am just recently getting more familiar with the webpack ecosystem so any guidance is much appreciated.
Okay!
I worked this out by looking around here:
https://github.com/facebookincubator/create-react-app/blob/master/packages/react-dev-utils/webpackHotDevClient.js
Many thanks to the create-react-app team for their judicious use of comments.
I created a slimmed down version of this specifically for handling the reload condition for extension development.
var SockJS = require('sockjs-client')
var url = require('url')
// Connect to WebpackDevServer via a socket.
var connection = new SockJS(
url.format({
// Default values - Updated to your own
protocol: 'http',
hostname: 'localhost',
port: '3000',
// Hardcoded in WebpackDevServer
pathname: '/sockjs-node',
})
)
var isFirstCompilation = true
var mostRecentCompilationHash = null
connection.onmessage = function(e) {
var message = JSON.parse(e.data)
switch (message.type) {
case 'hash':
handleAvailableHash(message.data)
break
case 'still-ok':
case 'ok':
case 'content-changed':
handleSuccess()
break
default:
// Do nothing.
}
}
// Is there a newer version of this code available?
function isUpdateAvailable() {
/* globals __webpack_hash__ */
// __webpack_hash__ is the hash of the current compilation.
// It's a global variable injected by Webpack.
return mostRecentCompilationHash !== __webpack_hash__
}
function handleAvailableHash(data){
mostRecentCompilationHash = data
}
function handleSuccess() {
var isHotUpdate = !isFirstCompilation
isFirstCompilation = false
if (isHotUpdate) { handleUpdates() }
}
function handleUpdates() {
if (!isUpdateAvailable()) return
console.log('%c Reloading Extension', 'color: #FF00FF')
chrome.runtime.reload()
}
When you are ready to use it (during development only) you can simply add it to your background.js entry point
module.exports = {
entry: {
background: [
path.resolve(__dirname, 'reloader.js'),
path.resolve(__dirname, 'background.js')
]
}
}
For actually hooking into the event emitter as was originally asked you can just require it from webpack/hot/emitter since that file exports an instance of the EventEmitter that's used.
if(module.hot) {
var lastHash
var upToDate = function upToDate() {
return lastHash.indexOf(__webpack_hash__) >= 0
}
var clientEmitter = require('webpack/hot/emitter')
clientEmitter.on('webpackHotUpdate', function(currentHash) {
lastHash = currentHash
if(upToDate()) return
console.log('%c Reloading Extension', 'color: #FF00FF')
chrome.runtime.reload()
})
}
This is just a stripped down version straight from the source:
https://github.com/webpack/webpack/blob/master/hot/dev-server.js
I've fine-tuned the core logic of the crx-hotreload package and come up with a build-tool agnostic solution (meaning it will work with Webpack but also with anything else).
It asks the extension for its directory (via chrome.runtime.getPackageDirectoryEntry) and then watches that directory for file changes. Once a file is added/removed/changed inside that directory, it calls chrome.runtime.reload().
If you'd need to also reload the active tab (when developing a content script), then you should run a tabs.query, get the first (active) tab from the results and call reload on it as well.
The whole logic is ~35 lines of code:
/* global chrome */
const filesInDirectory = dir => new Promise(resolve =>
dir.createReader().readEntries(entries =>
Promise.all(entries.filter(e => e.name[0] !== '.').map(e =>
e.isDirectory
? filesInDirectory(e)
: new Promise(resolve => e.file(resolve))
))
.then(files => [].concat(...files))
.then(resolve)
)
)
const timestampForFilesInDirectory = dir => filesInDirectory(dir)
.then(files => files.map(f => f.name + f.lastModifiedDate).join())
const watchChanges = (dir, lastTimestamp) => {
timestampForFilesInDirectory(dir).then(timestamp => {
if (!lastTimestamp || (lastTimestamp === timestamp)) {
setTimeout(() => watchChanges(dir, timestamp), 1000)
} else {
console.log('%c ๐ Reloading Extension', 'color: #FF00FF')
chrome.runtime.reload()
}
})
}
// Init if in dev environment
chrome.management.getSelf(self => {
if (self.installType === 'development' &&
'getPackageDirectoryEntry' in chrome.runtime
) {
console.log('%c ๐ฆ Watching for file changes', 'color: #FF00FF')
chrome.runtime.getPackageDirectoryEntry(dir => watchChanges(dir))
}
})
You should add this script to your manifest.json file's background scripts entry:
"background": ["reloader.js", "background.js"]
And a Gist with a light explanation in the Readme: https://gist.github.com/andreasvirkus/c9f91ddb201fc78042bf7d814af47121
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)