Jspm and jspm-server hot reloading error: "Change to X cannot be handled gracefully" & "Change occurred to a file outside SystemJS loading" - jspm

I've written a simple es6 module which I'm trying to get Hot-reloading using jspm + jspm-server (fork of live-server). Accorcding to the docs, to mark any es6 file as hotreloadable I set:
export let __hotReload = true
When jspm-server first loads, the modules work fine. But when I make a change I get the following error
$ node test/server.js
Serving "/Users/ashleycoleman/github/inbro" at http://127.0.0.1:8080
🤘 Client connected. JSPM watching enabled
Change detected: test/async-dom-operation.js
✅ SystemJS loaded. Initialising ChangeHandler
# Then the below error occurs when I make a change to "async-dom-operation.js"
💥 Change to http://127.0.0.1:8080/test/async-dom-operation.js cannot be handled gracefully:
👉 Change occurred to a file outside SystemJS loading
This is my project setup:
.
├── config.js
├── package.json
└── test
├── async-dom-operation.js
├── index.html
├── main.js
└── server.js
server.js:
var jspmServer = require("jspm-server");
var params = {
host: "0.0.0.0", // Set the address to bind to. Defaults to 0.0.0.0.
open: '/test/' // When false, it won't load your browser by default.
};
jspmServer.start(params);
main.js:
import {asyncDomOperation} from '/test/async-dom-operation.js';
export let __hotReload = true; // For jspm-server hot reloading
asyncDomOperation();
async-dom-operation.js:
export function asyncDomOperation() {
var writePara = (msg) => () => document.writeln('<p>'+msg+'</p>');
setTimeout( writePara('Start...'), 100 );
setTimeout( writePara('...middle'), 200 );
setTimeout( writePara('...end'), 300 );
}
export let __hotReload = true; // For jspm-server hot reloading
config.js:
System.config({
baseURL: "/",
defaultJSExtensions: true,
transpiler: "babel",
babelOptions: {
"optional": [
"runtime",
"optimisation.modules.system"
]
},
paths: {
"github:*": "jspm_packages/github/*",
"npm:*": "jspm_packages/npm/*"
},
map: { ... etc ...}
});

this is definitely not the right answer, but I am the author of https://github.com/capaj/jspm-hot-reloader and I would be quite pleased if you tried your usecase with it and let me knwo if there are any issues. It is quite possible, that jspm-hot-reloader will be a part of JSPM 0.17.0 and I would love it if we could cover your usecase as well.

Related

Unit test for aws lambda using jest

const invokeApi = require("/opt/nodejs/kiwiCall");
const decrypt = require("/opt/nodejs/encryption");
const cors = require("/opt/nodejs/cors");
When I am testing my index.js file by manual mocking these dependencies in mocks directory as follows:
__mocks__
|_invokeApi
|_decrypt
|_cors
it says
FAIL ./index.test.js
● Test suite failed to run
Cannot find module '/opt/nodejs/kiwiCall' from 'index.js'
However, Jest was able to find:
'../../../../lambdas/Flights/Locations/index.js'
You might want to include a file extension in your import, or update your 'moduleFileExtensions', which is currently ['js', 'json', 'jsx', 'ts', 'tsx', 'node'].
See https://jestjs.io/docs/en/configuration#modulefileextensions-array-string
1 | "use strict";
2 |
> 3 | const invokeApi = require("/opt/nodejs/kiwiCall");
Wanted to know how can I mock the dependencies of AWS lambda in inedx.test.js file
In your package.json or jest.config you could add a moduleNameMapper for that directory.
"jest": {
"moduleNameMapper": {
"/opt/nodejs/(.*)": "<rootDir>/../nodejs/$1"
},
},
So I managed to figure out something based on my repository.
I'm using the moduleNameMapper to map the absolute path to another location in my repository to where I have the layer stored.
Eg.
moduleNameMapper: {'^/opt/config/config': '<rootDir>/src/layers/layers-core/config/config'}
In your case you could use a regex expression to match /opt/nodejs/ and map it elsewhere. Hope that helped.
EDIT:
I completely changed my approach and used babel-plugin-module-resolver with babel-rewire. I did this because the above method was incompatible with rewire. It's quite easy setup and you just need to setup a babel alias within .babelrc.
eg.
{
"plugins": [
["rewire"],
["babel-plugin-module-resolver", {
"alias": {
"/opt/config/config": "./src/layers/layers-core/config/config",
"/opt/utils/util-logger": "./src/layers/layers-core/utils/util-logger",
"/opt/slack": "./src/layers/layers-slack/slack"
}
}]
]
}
Combine this with IDE jsconfig.json path alias and you get full IDE support.
{
"compilerOptions": {
"module": "commonjs",
"target": "es2018",
"baseUrl": "./",
"paths": {
"/opt/config/config": ["src/layers/layers-core/config/config"],
"/opt/utils/util-logger": ["src/layers/layers-core/utils/util-logger"],
"/opt/slack/*": ["src/layers/layers-slack/slack/*"],
}
},
"exclude": ["node_modules", "dist"]
}
You can then reference your layers with jest.doMock('/opt/config/config', mockConfig);
EDIT 2:
Found a way to get Jest to mock it. Just slip {virtual: true} into the mock!
jest.doMock('/opt/config/config', mockConfig, {virtual: true});
I have pretty much the same issue. I have defined a layer which contains common code that's shared between other functions in my project. My project structure looks something like this:
project/
functions/
function1/
app.js
function2/
app.js
shared/
shared.js
I import my shared library like this:
const { doSomething } = require('/opt/shared');
exports.handler = async (event) => {
const result = await doSomething();
// etc...
return {statusCode: 200};
}
This works when I deploy to AWS Lambda because the /opt/shared exists and it can be referenced correctly. It also works if I run this on my machine using sam local invoke Function1 because it's running in a container, which makes /opt/shared available to the code.
However, I'm struggling to work out how I can mock this dependency in a unit test. If I simply do this: jest.mock('/opt/shared'), I'm getting: Cannot find module '/opt/shared' from app.test.js
You can use the modulePaths option, from this post.
Documentation
jest.config.js
"jest": {
"modulePaths": [
"<rootDir>/src/layers/base/nodejs/node_modules/"
]
}
You can dynamically create this array by scanning a directory
const testFolder = './functions/';
const fs = require('fs');
const modulePaths = fs.readdirSync(testFolder)
.reduce((modulePaths, dirName) => {
modulePaths.push(`functions/${dirName}/dependencies/nodejs/node_modules/`);
return modulePaths;
}, []);

How do I get webpack working with electron using aurelia?

right now I'm just trying to add electron to the basic hello world app (well, I did tweak some options in the aurelia cli, but still it's just at hello world webpack+typescript).
my current attempt is to use webpack-electron, what I'm getting is a white screen of death. I can also get a black screen of death, if I exclude the renderer, it can't find any of the resource files in that case, it's looking for them at the wrong path.
here's my src/main/app.ts
import { app, BrowserWindow } from "electron";
import * as path from "path";
let mainWindow: Electron.BrowserWindow;
const isDevelopment = process.env.NODE_ENV !== 'production';
function createWindowUrl(url) {
const prefix = isDevelopment
? `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`
: `file://${__dirname}`;
return `${prefix}/${url}`;
}
function createWindow() {
// Create the browser window.
mainWindow = new BrowserWindow({
height: 600,
width: 800,
webPreferences: {
nodeIntegration: true,
}
});
// and load the index.html of the app.
mainWindow.loadURL(createWindowUrl('../index.html'));
// Open the DevTools.
mainWindow.webContents.openDevTools();
// Emitted when the window is closed.
mainWindow.on("closed", () => {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
});
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on("ready", createWindow);
// Quit when all windows are closed.
app.on("window-all-closed", () => {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== "darwin") {
app.quit();
}
});
app.on("activate", () => {
// On OS X it"s common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow();
}
});
// In this file you can include the rest of your app"s specific main process
// code. You can also put them in separate files and require them here.
and my src/renderer/main.ts which I'm sure is wrong per https://medium.com/kendraio/using-angular-with-electron-webpack-b9763903823c
import {} from "../main"
I don't really care if I use webpack-electron, but how do I get aurelia working with electron in a way that also preserves the normal website/server code?
versions, but I doubt they matter
Calebs-MBP:warmaster calebcushing$ yarn list --depth=0 --pattern "^webpack|^aurelia|^electron"
yarn list v1.21.1
├─ aurelia-animator-css#1.0.4
├─ aurelia-binding#2.5.2
├─ aurelia-bootstrapper#2.3.3
├─ aurelia-cli#1.2.3
├─ aurelia-dependency-injection#1.5.2
├─ aurelia-event-aggregator#1.0.3
├─ aurelia-framework#1.3.1
├─ aurelia-history-browser#1.4.0
├─ aurelia-history#1.2.1
├─ aurelia-hot-module-reload#0.2.1
├─ aurelia-loader-default#1.2.1
├─ aurelia-loader-webpack#2.2.1
├─ aurelia-loader#1.0.2
├─ aurelia-logging-console#1.1.1
├─ aurelia-logging#1.5.2
├─ aurelia-metadata#1.0.6
├─ aurelia-pal-browser#1.8.1
├─ aurelia-pal#1.8.2
├─ aurelia-path#1.1.5
├─ aurelia-polyfills#1.3.4
├─ aurelia-route-recognizer#1.3.2
├─ aurelia-router#1.7.1
├─ aurelia-task-queue#1.3.3
├─ aurelia-templating-binding#1.5.3
├─ aurelia-templating-resources#1.13.0
├─ aurelia-templating-router#1.4.0
├─ aurelia-templating#1.10.3
├─ aurelia-testing#1.0.0
├─ aurelia-tools#2.0.0
├─ aurelia-webpack-plugin#3.0.0
├─ electron-builder#22.3.2
├─ electron-devtools-installer#2.2.4
├─ electron-publish#22.3.2
├─ electron-to-chromium#1.3.345
├─ electron-webpack-js#2.3.4
├─ electron-webpack#2.7.4
├─ electron#8.0.0
├─ webpack-bundle-analyzer#3.6.0
├─ webpack-cli#3.3.10
├─ webpack-dev-middleware#3.7.2
├─ webpack-dev-server#3.10.3
├─ webpack-log#2.0.0
├─ webpack-merge#4.2.2
├─ webpack-sources#1.4.3
└─ webpack#4.41.5
✨ Done in 1.03s.
So this is probably not a be-all end all but I got the hello world to display in electron, so here's what I did
TL;DR;
change the webpack.config.js baseUrl to be '' (an empty string)
add these to package.json with your package manager (I'm not sure if electron-builder is required)
"electron": "^8.0.0",
"electron-builder": "^22.3.2",
"electron-webpack": "^2.7.4",
...scripts
"build:electron": "npm run build && electron-webpack app",
"package:electron": "npm run build:electron && electron-builder",
"start:electron": "npm run build:dev && electron-webpack dev",
...// electron webpack and builder configuration
"electronWebpack": {
"commonSourceDirectory": "dist",
"staticSourceDirectory": "static",
"title": true
},
"build": {
"directories": {
"buildResources": "dist",
"output": "electron"
},
"files": [ // actually include the dist folder
{
"from": "dist",
"to": "dist"
}
]
},
"main": "main.js",
then add a src/main/app.ts and a src/main/renderer.ts (renderer will remain an empty file)
in src/main/app.ts add this code which is basically the electron typescript quickstart code with one change. The file loaded it just ../index.html, __dirname will look in the wrong place.
import { app, BrowserWindow } from "electron";
import * as path from "path";
import { format as formatUrl } from 'url';
let mainWindow: Electron.BrowserWindow;
function createWindow() {
// Create the browser window.
mainWindow = new BrowserWindow({
height: 600,
width: 800,
});
const isDevelopment = process.env.NODE_ENV !== 'production';
// Open the DevTools.
mainWindow.webContents.openDevTools();
// and load the index.html of the app.
// this conditional is silly, but was the only way I figured out how to have it work in both dev and actually packaging the app
if (isDevelopment) {
mainWindow.loadFile(path.relative(__dirname, 'dist/index.html'))
} else {
mainWindow.loadURL(formatUrl({
pathname: path.join(__dirname, 'dist/index.html'),
protocol: 'file',
slashes: true
}));
}
// Emitted when the window is closed.
mainWindow.on("closed", () => {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
});
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on("ready", createWindow);
// Quit when all windows are closed.
app.on("window-all-closed", () => {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== "darwin") {
app.quit();
}
});
app.on("activate", () => {
// On OS X it"s common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow();
}
});
// In this file you can include the rest of your app"s specific main process
// code. You can also put them in separate files and require them here.
and then change webpack.config.js as previously stated and try npm run start and npm run start:electron and both should now run.
using Capacitor for this is far easier, just follow this document.
Then add electron-builder as dev to the electron project added by capacitor. Add these scripts to package your app, and you're good to go.
{
"scripts": {
"pack": "electron-builder --dir",
"dist": "electron-builder"
}
}

Including a shared project in create-react-app

In my project i have the following folder/project structure.
Project
├── client (create-react-app)
│ ├── tsconfig.json
│ └── packages.json
├── server
│ ├── tsconfig.json
│ └── packages.json
└── shared
├── tsconfig.json
└── packages.json
The shared project is mostly interface/class type declarations that i use in both the front and backend so they use the same object type.
I was including the shared project in both client and server using the referenced projects from typescript.
tsconfig.json
...
},
"references": [
{
"path": "../shared"
}
],
Although upon trying to use one of the imported types in a useReducer hook:
Component in client/src
import React, { useReducer, useEffect } from 'react';
import { IRoadBook, GetNewRoadBook} from '../../../shared/src/types/IRoadBook';
import { Grid, TextField, Button } from '#material-ui/core';
import { useParams } from 'react-router-dom';
type State = {
RoadBook: IRoadBook | any;
}
export default function RoadBookEditor() {
const { objectId } = useParams();
const [state, dispatch] = useReducer(reducer, {RoadBook : GetNewRoadBook()});
....
The following error happens upon starting the project :
"Module not found: You attempted to import ../../../shared/src/types/IRoadBook which falls outside of the project src/ directory. Relative imports outside
of src/ are not supported."
Which from what i read is a limitation imposed by create-react-app configurations.
If i do
const [state, dispatch] = useReducer(reducer, {RoadBook :{}});
Code builds/runs successfuly. (causes visual issues down the road but that is not the point of this question).
Question : What is the proper way to include this shared project in my create-react-app client project?
shared/types/IRoadBook.tsx
export interface IRoadBook {
_id: string;
Name: string;
Description: string;
}
export function GetNewRoadBook(): IRoadBook {
return { _id: '', Name: '', Description: '' } as IRoadBook;
}
If I understood correctly what you're looking for is a monorepo setup.
Out of the box create-react-app does not support importing code from outside your source folder. To achieve it you need to modify the webpack config inside it, and there are a couple of alternatives for that:
1- Using something like customize-cra, craco, etc.
2- forking CRA and modifying react-scripts (https://create-react-app.dev/docs/alternatives-to-ejecting/)
3- Ejecting and modifying the webpackconfig
for 2 and 3, you'll need to remove ModuleScopePlugin from webpack config and add the paths to babel-loader.
A few other places you can get a direction:
Create React App + Typescript In monorepo code sharing
https://blog.usejournal.com/step-by-step-guide-to-create-a-typescript-monorepo-with-yarn-workspaces-and-lerna-a8ed530ecd6d

Versioning Nestjs routes?

I'm just getting started with Nestjs and am wondering how I can version my API using either a route prefix or through an Express Router instance?
Ideally, I would like to make endpoints accessible via:
/v1
/v2
etc, so I can gracefully degrade endpoints. I'm not seeing where I could add the version prefix. I know it's possible to set a global prefix on the application instance, but that's not for a particular set of endpoints.
Here's an open discussion about the RouterModule https://github.com/nestjs/nest/issues/255. I understand how important this functionality is, so it should appear in the near future. At this point it is necessary to put v1 / v2 directly into the #Controller() decorator.
Router Module comes to rescue, with Nest RouterModule it's now a painless organizing your routes.
See How it easy to setup.
const routes: Routes = [
{
path: '/ninja',
module: NinjaModule,
children: [
{
path: '/cats',
module: CatsModule,
},
{
path: '/dogs',
module: DogsModule,
},
],
},
];
#Module({
imports: [
RouterModule.forRoutes(routes), // setup the routes
CatsModule,
DogsModule,
NinjaModule
], // as usual, nothing new
})
export class ApplicationModule {}
this will produce something like this:
ninja
├── /
├── /katana
├── cats
│ ├── /
│ └── /ketty
├── dogs
├── /
└── /puppy
and sure, for Versioning the routes you could do similar to this
const routes: Routes = [
{
path: '/v1',
children: [CatsModule, DogsModule],
},
{
path: '/v2',
children: [CatsModule2, DogsModule2],
},
];
Nice !
check it out Nest Router
for version or any prefix, you can use "global prefix":
https://docs.nestjs.com/faq/global-prefix
according to latest docs inside main.ts after const app = await NestFactory.create(AppModule) use
// Versioning
app.enableVersioning({
type: VersioningType.URI,
defaultVersion: '1',
prefix: 'api/v',
});
This will give all your routes a default prefix of /api/v1 unless specified
To override version in controller use
#Controller({version:'2'}) decorator on controller class
For overriding version at route level use #Version('2') above controller method
Note: If you are using swagger make sure to call app.enableVersioning() before SwaggerModule.createDocument()
Link: https://docs.nestjs.com/techniques/versioning
Best and simple way to do this is using global prefix
An example is given below :
import { VersioningType } from "#nestjs/common";
app.enableVersioning({
type: VersioningType.URI,
});
app.setGlobalPrefix("api/v1"); //edit your prefix as per your requirements!
You can exclude routes from the global prefix using the following construction:
app.setGlobalPrefix('v1', {
exclude: [{ path: 'health', method: RequestMethod.GET }], // replace your endpoints in the place of health!
});
Alternatively, you can specify route as a string (it will apply to every request method):
app.setGlobalPrefix('v1', { exclude: ['cats'] }); // replace your endpoints in the place of cats!

Using Benchmarkjs with Webpack and Babel

I'm trying to get some basic benchmark tests working and am having trouble figuring out the right configuration. I'm trying to use Benchmarkjs with webpack and babel to transpile my code to es5. I created a benchmarks.webpack.js as an entry point which looks like this:
var context = require.context('./src/js', true, /-benchmark\.js$/);
context.keys().forEach(context);
module.exports = context;
I then have a benchmark file that I want to run (test-benchmark.js):
import benchmark from 'benchmark';
import benchmarks from 'beautify-benchmark';
let suite = new benchmark.Suite;
suite.add('RegExp#test', function() {
/o/.test('Hello World!');
})
.add('String#indexOf', function() {
'Hello World!'.indexOf('o') > -1;
})
.on('cycle', function(event) {
benchmarks.add(event.target);
})
.on('complete', function() {
benchmarks.log();
})
.run();
I updated my webpack build to try and transpile the benchmarks:
_.assign(config, {
devtool: 'eval-cheap-module-source-map',
output: {
path: path.join(__dirname, 'build/benchmark'),
filename: 'benchmark.js',
publicPath: '/'
},
entry: [
'./benchmarks.webpack.js'
],
plugins: [
],
module: {
loaders: [
{
test: /\.js$/,
loaders: ['babel?stage=0'],
include: path.join(__dirname, 'src/js')
},
]
},
});
Finally, I want to be able run this from an npm script:
"scripts": {
"bench": "webpack --config webpack.bench.config.js && node build/benchmark/benchmark.js"
},
However, I'm getting warnings that the result of the benchmark dependency is an expression and there no suitable loaders for the .json, .txt, etc files. I tried hacking up Benchmarkjs to export correctly but was not successful.
WARNING in ./~/benchmark/benchmark.js
Critical dependencies:
1122:34-49 the request of a dependency is an expression
# ./~/benchmark/benchmark.js 1122:34-49
WARNING in ./~/benchmark/package.json
Module parse failed: /home/bill/dev/levelstory/react-client-redux/node_modules/benchmark/package.json Line 2: Unexpected token :
You may need an appropriate loader to handle this file type.
| {
| "name": "benchmark",
| "version": "1.0.0",
| "description": "A benchmarking library that works on nearly all JavaScript platforms, supports high-resolution timers, and returns statistically significant results.",
# ./~/benchmark ^\.\/.*$
WARNING in ./~/benchmark/LICENSE.txt
Module parse failed: /home/bill/dev/levelstory/react-client-redux/node_modules/benchmark/LICENSE.txt Line 1: Unexpected number
You may need an appropriate loader to handle this file type.
| Copyright 2010-2012 Mathias Bynens <http://mathiasbynens.be/>
| Based on JSLitmus.js, copyright Robert Kieffer <http://broofa.com/>
| Modified by John-David Dalton <http://allyoucanleet.com/>
# ./~/benchmark ^\.\/.*$
Looks like benchmark does something special with require. That messes it up for Webpack. It has the following lines:
var freeRequire = typeof require == 'function' && require;
...
function req(id) {
try {
var result = freeExports && freeRequire(id);
} catch(e) { }
return result || null;
}
If you comment out the function contents, the error goes away. Given it's not ideal to patch around it this way I would poke the benchmark guys about this directly instead. Perhaps there's something we're missing.

Resources