Watch project dependencies using VSCode API - javascript

I am writing a VSCode extension and I need a way to know when a project gets a new dependency to trigger some action. For that, I decided to watch package.json file using 'fs.watchFile'. But the problem is that fs sees the change only after saving the file and it takes a second or two. Moreover, if a user adds a new dependency manually to package.json there is no change event until the user saves it. I wonder if VSCode has some internal API that will do it better than fs.

VSCode has a nice utility for that vscode.workspace.createFileSystemWatcher. It's better than fs implementation because it is also triggered when the file is 'dirty' before it is saved. Possible implementation is:
const watcher = vscode.workspace.createFileSystemWatcher(
packageJsonPath, // absolute path to package.json
true, // ignore create events
false, // don't ignore change events
true, // ignore delete events
);
watcher.onDidChange(() => {
// trigger some action
})
// when not needed
if (watcher) {
watcher.dispose();
}

Related

React/nextJS: How to debug different nodes of SSR react application?

I'm running a nextJS application, which is running SSR.
But as I do get the error:
Warning: Did not expect server HTML to contain a <div> in <div>.
So there seems to be a difference between the server-side and the client side nodes. How can I find those differences?
This is the repo of an example app:
https://github.com/jaqua/nextjs-app
Just run npm install and npm run dev
As comparing two html manually can be rather cumbersome depending on the size of your page, it's advised to first assess what could be wrong rather than brute-forcing. From my experience in 99% of the cases an SSR mismatch occurs when you either:
Included and rendered a Component which doesn't behave the same way on the client and the server (e.g they use global variables to determine where the code is being run and conditionally render elements based on that). For example there was a clipboard module that would only work on the client because it would use a variable of window.
Rendering of data fetched from an asynchronous source which is only present on either the server or the client. You need to make the same data available for both during the initial render.
If nothing comes out to mind after this, you need to proceed by elimination. In case the error occurs on every page, it is likely to be a result of a misconfiguration of the server. For example, are you doing your own renderToString? Double check you didn't add an extra nested div in there, the string should be right inside the element you mount React on.
If that is not the case, try to extract one by one the components you are rendering, and you should be able to narrow down pretty quickly which is causing your issue.
Also keep in mind that you would need to restart your server every-time you make a change (unless you have a nodemon or similar config reloading the server-side code when you modify your source) for it to be applied!
As a last resort, you could potentially make your own diff between the server response and the client first render.
1) Open your console from your site, and paste the following:
console.log(document.documentElement.innerHTML)
2) Click on the Copy button, and paste that in a client.html file
3) Now run in your terminal:
curl YOUR_URL > server.html
4) It's likely the server will return you a minified version of your html, so you need to indent it in order to make it match with your client html, use something like this for that purpose.
5) Once you've done this, you can now run the actual diff in your terminal:
diff server.html client.html
This will list you every part of the files that differ between each other.
You can ignore diffs related to Javascript as the indenting will most likely be bad anyway, but concentrate on the html ones, where you might be able to spot differences and infer what is going wrong.
In your case, your translation system is likely to be the root cause of the issue. I would advice to follow more standard practices rather than next-i18next which seem pretty new and more likely to have problems. Someone else apparently also has an issue with SSR, and to be honest stuff like this is quite scary.
I know it can look a bit troublesome to setup, but here is my own i18n config which can be required either on the server or the client provided you specify a global variable to determine one which environment you are (here __BROWSER__).
import i18n from 'i18next'
import LanguageDetector from 'i18next-browser-languagedetector'
import { reactI18nextModule } from 'react-i18next'
i18n
.use(require(__BROWSER__ ? 'i18next-xhr-backend' : 'i18next-node-fs-backend'))
.use(LanguageDetector)
.use(reactI18nextModule)
.init({
fallbackLng: 'en',
ns: ['translations'],
defaultNS: 'translations',
interpolation: {
escapeValue: false,
},
react: {
wait: true,
},
backend: {
loadPath: __BROWSER__
? '/locales/{{lng}}/{{ns}}.json'
: require('path').join(__dirname, '/locales/{{lng}}/{{ns}}.json'),
},
})
export default i18n
You simply need to use the middleware, serve the locales from your server so the client can load them from xhr and have the I18nextProvider require the i18n instance. The full SSR docs are here.
I would start by looking at the html that get's to the browser(network tab in chrome devtools), then react is probably rendering client side anyway, so you can see the current DOM after the client side render and compare (go to elements tab in chrome devtools -> right click the html element and select "copy> copy outterHTML")
If that fails, you can try adding breakpoints in the browser inside react itself:
function canHydrateInstance # ReactDOMHostConfig.js
https://github.com/facebook/react/blob/c954efa70f44a44be9c33c60c57f87bea6f40a10/packages/react-dom/src/client/ReactDOMHostConfig.js
possibly relevant links to same kind of issue:
React 16 warning "warning.js:36 Warning: Did not expect server HTML to contain a <div> in <div>."
https://github.com/zeit/next.js/issues/5367

Cypress and Script Injection inside test scenario

I am pretty new to Cypress and at the moment I am trying to test a webpage that uses browser extension I created. This extension only injects a set of JS and CSS files to the webpage and I want to simulate the same thing in my integration tests to be able to inject the libraries and test the behavior. I was wondering if there is a way to access document object from Cypress test to inject CSS or JavaScript to the head of the webpage.
Yes, there is. Cypress is actually running in the browser, and although commands are queued asynchronously, you can queue up native JS code to be run, like so:
cy.get("html").then(() => {
document.querySelector("div.myDiv").innerHTML = "...";
// ...
});
If you are trying to target or modify a specific element, you can get it via Cypress to take advantage of automatic retries to wait for the element to exist before operating on it:
cy.get("div.myDiv").then(elem => {
elem.innerHTML = "...";
// ...
});

How to programmatically set download path in Protractor?

I am trying to dynamically set the Chrome download path in conf.js for Protractor. Our webservice exports a file and I am writing a test that needs to know where the download file is going to be in order to verify it. Right now, I am hard setting the browser's download path. The problem is that other members of my team and the build machines will also be running this test and there is no single download path I could choose that would work on every dev and build machine. After doing some reading, I thought the best solution would be get the user data directory from the getCapabilities() function inside the onPrepare function, and then set that as the download directory, like so:
onPrepare: function () {
var jasmineReporters = require('jasmine-reporters');
jasmine.getEnv().addReporter(new jasmineReporters.JUnitXmlReporter( {
savePath: 'reports', consolidateAll: true } ));
var cap = browser.getCapabilities();
// Set prefsDict using cap.caps_.userDataDir
},
capabilities: {
'chromeOptions': {
'prefs': prefsDict
}
}
This would allow the code to be dynamic, but getCapabilities returns a promise, so the code above is not going to work because conf.js will finish constructing the config object before the promise resolves. Using a then function on getCapabilities doesn't help because I can't construct the capabilities section of my config object in the then function. I can't call getCapabilities outside of the onPrepare function because conf.js itself doesn't have context for it. Setting a network path is also not feasible for the team's setup.
Has anyone else tackled something like this? Is there any other way to programmatically set the download path for Chrome?
This probably doesn't solve the issue in the way you'd like, but you could run
protractor conf.js --capabilities.chromeOptions.prefs 'path/to/user/folder'
if the user is savvy enough to know, find, or store that information.
Edit:
You might be able to use .execute() to force the browser.getCapabilities(); to fulfill before moving to the next statement.
Normally called by protractor.promise.controlFlow().execute( myPromise )
However, I think execute() also returns a promise, so you might be back to square one with this idea.

Auto Update without "standard-app-packages"

How can I have Auto Updates without the "standard-app-packages" package? I have tried adding the "autoupdate" package without success.
The standard-app-packages package seems to do some magic which I'm not sure how to do without including it i.e.
// These are useful too! But you don't have to see their exports
// unless you want to.
api.use([
// We can reload the client without messing up methods in flight.
'reload',
// And update automatically when new client code is available!
'autoupdate'
], ['client', 'server']);
standard-app-packages is actually all of the following packages:
You can remove it but you have to add back the pieces of it you want:
List of packages in standard-app-packages
meteor
webapp
logging
deps
session
livedata
mongo-livedata
ui
spacebars
templating
check
underscore
jque
rand
ejson
reload
autoupdate
So you can remove it and add back reload and autoupdate, but then you may need the meteor package too! It depends more on what you want exactly.

How can I edit on my server files without restarting nodejs when i want to see the changes?

I'm trying to setup my own nodejs server, but I'm having a problem. I can't figure out how to see changes to my application without restarting it. Is there a way to edit the application and see changes live with node.js?
Nodules is a module loader for Node that handles auto-reloading of modules without restarting the server (since that is what you were asking about):
http://github.com/kriszyp/nodules
Nodules does intelligent dependency tracking so the appropriate module factories are re-executed to preserve correct references when modules are reloaded without requiring a full restart.
Check out Node-Supervisor. You can give it a collection of files to watch for changes, and it restarts your server if any of them change. It also restarts it if it crashes for some other reason.
"Hot-swapping" code is not enabled in NodeJS because it is so easy to accidentally end up with memory leaks or multiple copies of objects that aren't being garbage collected. Node is about making your programs accidentally fast, not accidentally leaky.
EDIT, 7 years after the fact: Disclaimer, I wrote node-supervisor, but had handed the project off to another maintainer before writing this answer.
if you would like to reload a module without restarting the node process, you can do this by the help of the watchFile function in fs module and cache clearing feature of require:
Lets say you loaded a module with a simple require:
var my_module = require('./my_module');
In order to watch that file and reload when updated add the following to a convenient place in your code.
fs.watchFile(require.resolve('./my_module'), function () {
console.log("Module changed, reloading...");
delete require.cache[require.resolve('./my_module')]
my_module = require('./my_module');
});
If your module is required in multiple files this operation will not affect other assignments, so keeping module in a global variable and using it where it is needed from global rather than requiring several times is an option. So the code above will be like this:
global.my_module = require ('./my_module');
//..
fs.watchFile(require.resolve('./my_module'), function () {
console.log("Module changed, reloading...");
delete require.cache[require.resolve('./my_module')]
global.my_module = require('./my_module');
});
Use this:
https://github.com/remy/nodemon
Just run your app like this: nodemon yourApp.js
There should be some emphasis on what's happening, instead of just shotgunning modules at the OP. Also, we don't know that the files he is editing are all JS modules or that they are all using the "require" call. Take the following scenarios with a grain of salt, they are only meant to describe what is happening so you know how to work with it.
Your code has already been loaded and the server is running with it
SOLUTION You need to have a way to tell the server what code has changed so that it can reload it. You could have an endpoint set up to receive a signal, a command on the command line or a request through tcp/http that will tell it what file changed and the endpoint will reload it.
//using Express
var fs = require('fs');
app.get('reload/:file', function (req, res) {
fs.readfile(req.params.file, function (err, buffer) {
//do stuff...
});
});
Your code may have "require" calls in it which loads and caches modules
SOLUTION since these modules are cached by require, following the previous solution, you would need a line in your endpoint to delete that reference
var moduleName = req.params.file;
delete require.cache[moduleName];
require('./' + moduleName);
There's a lot of caveats to get into behind all of this, but hopefully you have a better idea of what's happening and why.
What's “Live Coding”?
In essence, it's a way to alter the program while it runs, without
restarting it. The goal, however, is to end up with a program that
works properly when we (re)start it. To be useful, it helps to have an
editor that can be customized to send code to the server.
Take a look: http://lisperator.net/blog/livenode-live-code-your-nodejs-application/
You can also use the tool PM2. Which is a advanced production process tool for node js.
http://pm2.keymetrics.io/
I think node-inspector is your best bet.
Similar to how you can Live Edit Client side JS code in Chrome Dev tools, this utilizes the Chrome (Blink) Dev Tools Interface to provide live code editing.
https://github.com/node-inspector/node-inspector/wiki/LiveEdit
A simple direct solution with reference to all answers available here:
Node documentation says that fs.watch is more efficient than fs.watchFile & it can watch an entire folder.
(I just started using this, so not really sure whether there are any drawbacks)
fs.watch("lib", (event_type, file_name) => {
console.log("Deleting Require cache for " + file_name);
delete require.cache[ require.resolve("./lib/" + file_name)];
});

Categories

Resources