grunt-contrib-connect - undefined is not a function for connect.static - node.js

I am trying to configure the grunt connect such a way that
For static pages it serves pages from src directory
web service calls are intercepted by middle-ware and static json is served.
While the web service calls are being mocked correctly the connect.static call ends up giving an error
TypeError: undefined is not a function
While I realize that the connect.static was provided in later versions of this module, I have already upgraded to a version later than that
Here is my package.json file
{
"name": "my-angular-seed-project",
"version": "1.0.0",
"description": "angular seed with only bower and grunt",
"main": "index.js",
"dependencies": {
},
"devDependencies": {
"bower": "^1.4.1",
"grunt": "^0.4.5",
"grunt-cli": "^0.1.13",
"grunt-contrib-connect": ">=0.10.0",
"grunt-contrib-jshint": "latest",
"grunt-contrib-uglify": "latest",
"grunt-contrib-watch": "latest",
"jshint-stylish": "^2.0.1"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Here is the gruntfile.js
// Gruntfile.js
// our wrapper function (required by grunt and its plugins)
// all configuration goes inside this function
module.exports = function(grunt) {
var restEndPoints = {
"/restapi/users": {"GET":"json-files/users.get.json"},
"/restapi/users/login": {"GET":"json-files/users.get.json"},
"/restapi/users/john#gmail.com": {"GET":"json-files/users.get.john.json"},
"/restapi/nodes": {"GET":"json-files/nodes.get.json","PUT":"json-files/nodes.put.json","POST":"json-files/nodes.put.json"},
"/restapi/nodes/Node1": {"GET":"json-files/nodes.get.node1.json","DELETE":"json-files/nodes.delete.node1.json"},
"/restapi/services": {"GET":"json-files/services.get.json","PUT":"json-files/services.put.json","POST":"json-files/services.put.json"},
"/restapi/services/nginx": {"GET":"json-files/services.get.nginx.json","DELETE":"json-files/services.delete.nginx.json"},
"/restapi/commands": {"GET":"json-files/commands.get.json","PUT":"json-files/commands.put.json","POST":"json-files/commands.put.json"},
"/restapi/commands/pwd": {"GET":"json-files/commands.get.pwd.json","DELETE":"json-files/commands.delete.pwd.json"}
};
String.prototype.endsWith = function(suffix) {
return this.indexOf(suffix, this.length - suffix.length) !== -1;};
// ===========================================================================
// CONFIGURE GRUNT ===========================================================
// ===========================================================================
grunt.initConfig({
// get the configuration info from package.json ----------------------------
// this way we can use things like name and version (pkg.name)
pkg: grunt.file.readJSON('package.json'),
// all of our configuration will go here
watch: {
},
// configure jshint to validate js files -----------------------------------
jshint: {
options: {
reporter: require('jshint-stylish') // use jshint-stylish to make our errors look and read good
},
// when this task is run, lint the Gruntfile and all js files in src
build: ['Gruntfile.js', 'src/**/*.js']
},
// configure connect to run server (on test/serve or example)
connect: {
server: {
options: {
port : 8000,
hostname : 'localhost',
base : 'src',
middleware: function (connect,options){return [
//Middleware #1 - for rest api calls
function restapiMiddleware(req, res, next) {
if (req.url.indexOf('restapi') > 0){
console.log(req.method+' request received for webservice api ['+req.url+']');
var match = false;
var json_file_to_serve = "";
var keys = Object.keys(restEndPoints);
keys.forEach(function(urlAsKey) {
if (req.url.endsWith(urlAsKey)) {
Object.keys(restEndPoints[urlAsKey]).forEach(function(httpMethodsAsKey) {
if (req.method == httpMethodsAsKey){
match = true;
json_file_to_serve = restEndPoints[urlAsKey][httpMethodsAsKey];
}
}); //forEach ends
}
}); //forEach ends
//no match with the url, move along
if (match == false) {
return next();
}
if (req.url.endsWith('/login')){
res.writeHead(200, { 'user-auth-token':'56f7997504b352cbf6ba6210409e423f5fdac49a','user-enc-email':'lJUXityStsKko/lPr9eJUc5fLFCV5kFm' });
}
//Finalize this response with json file
res.end(grunt.file.read(json_file_to_serve));
// if not restapi call then goto next middleware
// can we serve static right here ?
}else{
return next();
}
} // element/middleware one ends so comma just json objects this is awesome
,
//Middleware #2 for static page calls
function staticMiddleware(connect,options) {
connect.static(options.base);
//connect.static('src');
}
] // array ends
}
}
}
}
});
// ===========================================================================
// LOAD GRUNT PLUGINS ========================================================
// ===========================================================================
// we can only load these if they are in our package.json
// make sure you have run npm install so our app can find these
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-watch');
//register the task
grunt.registerTask('serve', ['connect', 'watch']);
};
Am I missing something trivial here ?

Thanks #R4c00n & #Christian Fritz, I was going through the gruntfile of the grunt-contrib-connect and it uses the serveStatic call instead of connect.static and yes the module serve-static is part of grunt contrib connect's node_modules. So now a serveStatic(base.options) does wire the static files as well.
Here is the updated grunt file section (the serve static call has to be first though)
middleware: function (connect,options){return [
//statically serve pages from src directory
serveStatic('src'),
//Middleware #1 - for rest api calls
function restapiMiddleware(req, res, next) {
// middleware code
}];}

Related

Shopify node api context initalize errors out

I'm trying to make an app following these directions:
https://github.com/Shopify/shopify-node-api/blob/main/docs/getting_started.md
I have all the code configred and it looks like this:
// src/index.ts
import http from 'http';
import url from 'url';
import querystring from 'querystring';
import Shopify, { ApiVersion } from '#shopify/shopify-api';
require('dotenv').config();
const { API_KEY, API_SECRET_KEY, SCOPES, SHOP, HOST } = process.env
Shopify.Context.initialize({
API_KEY,
API_SECRET_KEY,
SCOPES: [SCOPES],
HOST_NAME: HOST.replace(/https?:\/\//, ""),
HOST_SCHEME: HOST.split("://")[0],
IS_EMBEDDED_APP: {boolean},
API_VERSION: ApiVersion.{version} // all supported versions are available, as well as "unstable" and "unversioned"
});
// Storing the currently active shops in memory will force them to re-login when your server restarts. You should
// persist this object in your app.
const ACTIVE_SHOPIFY_SHOPS: { [key: string]: string | undefined } = {};
async function onRequest(
request: http.IncomingMessage,
response: http.ServerResponse,
): Promise<void> {
const {headers, url: req_url} = request;
const pathName: string | null = url.parse(req_url).pathname;
const queryString: string = String(url.parse(req_url).query);
const query: Record<string, any> = querystring.parse(queryString);
switch (pathName) {
default:
// This shop hasn't been seen yet, go through OAuth to create a session
if (ACTIVE_SHOPIFY_SHOPS[SHOP] === undefined) {
// not logged in, redirect to login
response.writeHead(302, {Location: `/login`});
response.end();
} else {
response.write('Hello world!');
// Load your app skeleton page with App Bridge, and do something amazing!
}
return;
} // end of default path
} // end of onRequest()
http.createServer(onRequest).listen(3000);
Package JSON looks like this:
{
"name": "shopify-checkout-apit",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"#shopify/shopify-api": "^3.1.0"
},
"devDependencies": {
"#types/node": "^17.0.40",
"dotenv": "^16.0.1",
"typescript": "^4.7.3"
},
"scripts": {
"build": "npx tsc",
"prestart": "yarn run build",
"start": "node dist/index.js"
}
}
When I go to run the app with yarn start I get a ton of errors
PS C:\Users\kawnah\shopify-checkout-apit> yarn start yarn run v1.22.18
$ yarn run build $ npx tsc src/index.ts:17:27 - error TS1003:
Identifier expected.
17 API_VERSION: ApiVersion.{version} // all supported versions are
available, as well as "unstable" and "unversioned"
~
src/index.ts:18:1 - error TS1005: ',' expected.
18 }); ~
Found 2 errors in the same file, starting at: src/index.ts:17
error Command failed with exit code 2. info Visit
https://yarnpkg.com/en/docs/cli/run for documentation about this
command. error Command failed with exit code 2. info Visit
https://yarnpkg.com/en/docs/cli/run for documentation about this
command. PS C:\Users\kawnah\shopify-checkout-apit>
I have no idea what any of this means.
Typescript Error TS1003 when attempting to access object properties using bracket notation
Why does this trigger an Identifier Expected error in Typescript?
I tried deleting node modules and reinstalling but it didn't work.
How do you fix this?
the config needs to look like this
Shopify.Context.initialize({
API_KEY,
API_SECRET_KEY,
SCOPES: [SCOPES],
HOST_NAME: HOST.replace(/https?:\/\//, ""),
HOST_SCHEME: HOST.split("://")[0],
IS_EMBEDDED_APP: true,
API_VERSION: ApiVersion.October21 // all supported versions are available, as well as "unstable" and "unversioned"
});

newman, postman's cli runner, can not find a custom reporter

When I run newman with a custom reporter it can not find it, and the error states the reporter should be installed in the newman directory. I am on windows 10. It is named newman-reporter-csvconsole. Where is the newman default directory, to look for reporters?
the reporter package index.js
function csvconsole (emitter, reporterOptions, collectionRunOptions) {
emitter.on('start',function (err, args)
{ // on start of run, log to console
console.log('running a collection...');
});
}
module.exports = csvconsole;
I then install a local package
C:\Users<user>\AppData\Roaming\npm\node_modules\newman\newman-reporter-csvconsole>npm init -w newman-reporter-csvconsole -S
C:\Users<user>\AppData\Roaming\npm\node_modules\newman\newman-reporter-csvconsole>npm pack
C:\Users<user>\AppData\Roaming\npm\node_modules\newman>npm install -S ./csvconsoleReporter/newman-reporter-csvconsole-1.0.0.tgz
The package and pack-lock files
C:\Users<user>\AppData\Roaming\npm\node_modules\newman\package.json
"dependencies": {
...
"newman-reporter-csvconsole": "file:newman-reporter-csvconsole",
...
C:\Users<user>\AppData\Roaming\npm\node_modules\newman\package-lock.json
"dependencies": {
...
"newman-reporter-csvconsole": "file:newman-reporter-csvconsole",
...
"newman-reporter-csvconsole": {
"version": "1.0.0",
"license": "ISC"
},
...
"node_modules/newman-reporter-csvconsole": {
"resolved": "newman-reporter-csvconsole",
"link": true
},
...
"newman-reporter-csvconsole": {
"version": "file:newman-reporter-csvconsole"
},
module.exports = function csvconsole (emitter, reporterOptions, collectionRunOptions)
{
// emitter is is an event emitter that triggers the following events: https://github.com/postmanlabs/newman#newmanrunevents
// reporterOptions is an object of the reporter specific options. See usage examples below for more details.
// collectionRunOptions is an object of all the collection run options:
// https://github.com/postmanlabs/newman#newmanrunoptions-object--callback-function--run-eventemitter
emitter.on('start',function (err, args)
{ // on start of run, log to console
console.log('running a collection...');
});
}

What is the most simplest way of implementing a DELETE request using axios?

I have been unsuccessful in trying to figure out how to solve the following errors, (1st error:)'OPTIONS http://localhost:3000/lists/5a9dca48cebb5a4e5fc1bfe9 404 (Not Found)' and (2nd error:)'Failed to load http://localhost:3000/lists/5a9dca48cebb5a4e5fc1bfe9: Response for preflight has invalid HTTP status code 404.'.
Initially I defined my code along the same lines as the following: https://github.com/20chix/Hotel_System_Vue.js_Frontend/blob/master/src/components/Hello.vue
Seen quite a number of posts similar to my problem, but neither of their suggested solutions have worked for me.
I'm using Vue.js, Axios and Node.js in the back, my collection is defined as follows in MongoDb:
List: {_id:'', name:'', items:
[ {
title: '',
category: ''
}
]
}
GetList.vue:
methods: {
fetchLists(){
let uri = 'http://localhost:3000/lists';
axios.get(uri).then((response) => {
this.List = response.data;
console.log(this.List[3].items[0]);
console.log(this.List);
});
},
DELETE(a_list, id){
$("#myModal").modal('show');
this.list = a_list;
this._id = id;
},
deleteList : function(_id){
// let uri = 'http://localhost:3000/lists/'+_id;
// this.List.splice(_id, 1);
axios.delete('http://localhost:3000/lists/'+_id)
.then((response) => {
this.fetchLists();
//refreshes Application
// window.location.reload();
})
.catch((error) => {
console.log(error);
});
}
ListController:
exports.delete_a_list = function(req, res)=>{
console.log(req.params);
List.deleteOne({req.params.listId}, function(err, list){
if(err){res.json(err);};
else
{res.json({list: 'List successfully deleted'});}
};
});
UPDATE:
Upon running 'npm install cors --save', it was stored in my package.json .
server/package.json:
{
"name": "api",
"version": "1.0.0",
"description": ":)",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"keywords": [
":)"
],
"license": "ISC",
"devDependencies": {
"nodemon": "^1.17.1"
},
"dependencies": {
"cors": "^2.8.4",
"express": "^4.16.2",
"mongoose": "^5.0.8",
"npm": "^5.7.1"
}
}
UPDATE:
I tried the following too:
ObjectID = require('mongodb').ObjectID;
exports.delete_a_list = function(req, res){
// console.log(req.params);
List.deleteOne({
_id: ObjectID(req.params.listId)}, function(err, list){
if(err)
res.json(err);
res.json({list: 'List successfully deleted'});
});
};'
This returns the same error including:
xhr.js?ec6c:178 OPTIONS http://localhost:3000/lists/undefined 404 (Not Found)
dispatchXhrRequest # xhr.js?ec6c:178
xhrAdapter # xhr.js?ec6c:12
dispatchRequest # dispatchRequest.js?c4bb:59
Promise.then (async)
request # Axios.js?5e65:51
Axios.(anonymous function) # Axios.js?5e65:61
wrap # bind.js?24ff:9
deleteList # GetList.vue?c877:131
boundFn # vue.esm.js?efeb:190
click # GetList.vue?d584:124
invoker # vue.esm.js?efeb:2004
fn._withTask.fn._withTask # vue.esm.js?efeb:1802
:1 Failed to load http://localhost:3000/lists/undefined: Response for preflight has invalid HTTP status code 404.
createError.js?16d0:16 Uncaught (in promise) Error: Network Error
at createError (createError.js?16d0:16)
at XMLHttpRequest.handleError (xhr.js?ec6c:87)
Thank you guys for all your suggestions.
I found the following video: https://www.youtube.com/watch?v=NEFfbK323Ok, from The Net Ninja, and was able to get it to finally work upon changing my code to reflect his particular method:
listRoutes.js:
app.route('/lists/:_id')
.get(lists.read_a_list)
// .update(lists.update_a_list)
.delete(lists.delete_a_list);
listController.js:
exports.delete_a_list = function(req, res){
// console.log(req.params);
List.findByIdAndRemove({_id: req.params._id}).then(function(list){
res.send(list);
});
};
GetList.vue:
deleteList : function(_id, List){
axios.delete('http://localhost:3000/lists/'+_id, List)
.then(response => {
this.List.splice(index, 1);
//refreshes Application
// window.location.reload();
})
}
Your problem ist related to CORS (cross-origin-resource-sharing).
If you are using node with express then just include this middleware:
https://www.npmjs.com/package/cors
This query seems wrong:
List.deleteOne({req.params.listId}, ...
Can you try modifying it like this?:
List.deleteOne({_id: ObjectID(req.params.listId}), ...
(You need to have ObjectID declared somewhere up: ObjectID = require('mongodb').ObjectID)

Node registry path with electron-updater and Sinopia

I am currently working on an application running on Electron (former atom-shell), and trying to design a way to alert the user when a new update is available. To do this, I am using electron-updater in the way described in electron-updater-sample. I also configured Sinopia to be listening on http://localhost:4873/ (default behavior) and ran this commande line:
npm config set registry "http://localhost:4873"
I checked in the .npmrc file, the registry is properly set with the new value.
The problem I have is when I try to check for the update, I get this error message in console:
{ [HTTPError: Response code 404 (Not Found)]
message: 'Response code 404 (Not Found)',
code: undefined,
host: 'registry.npmjs.org',
hostname: 'registry.npmjs.org',
method: 'GET',
path: '/hacker-keyboard-electron',
statusCode: 404,
statusMessage: 'Not Found' }
So I believe I forgot something in the configuration of npm that makes the application listen to the regular path for npm rather than the Sinopia server. The question is what?
Please find below the code I am using:
foobar-generator
├── app
├── bower components
├── bower.json
├── index.html
├── index. js
├── main. js
├── nbproject
├── node modules
├── npm-debug.log
├── package.json
├── readme. md
└── sinopia
package.json
{
"name": "foobar-generator",
"version": "0.0.1",
"description": "A generator for foobar",
"main": "main.js",
"dependencies": {
"angular": "^1.4.7",
"bootstrap": "^3.3.5",
"chokidar": "^1.2.0",
"electron-debug": "^0.2.1",
"electron-packager": "^5.1.0",
"electron-plugins": "^0.0.4",
"electron-prebuilt": "^0.33.6",
"electron-rebuild": "^1.0.2",
"electron-updater": "^0.2.0",
"grunt": "^0.4.5",
"jquery": "^2.1.4"
},
"devDependencies": {},
"publishConfig": {
"registry": "http://localhost:4873/"
},
"registry": "http://localhost:4873/"
}
main.js
var appli = require('app');
var BrowserWindow = require('browser-window');
var updater = require('electron-updater');
var util = require('util');
// Report crashes to our server.
require('crash-reporter').start();
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
var mainWindow = null;
var loaded = false;
// Quit when all windows are closed.
appli.on('window-all-closed', function () {
// 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') {
appli.quit();
}
});
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
appli.on('ready', function () {
updater.on('ready', function () {
// Create the browser window.
mainWindow = new BrowserWindow({width: 800, height: 600});
// and load the index.html of the app.
mainWindow.loadUrl('file://' + __dirname + '/index.html');
mainWindow.openDevTools({detach: true});
mainWindow.on('closed', function () {
mainWindow = null;
});
});
updater.on('updateRequired', function () {
appli.quit();
});
updater.on('updateAvailable', function () {
if (mainWindow) {
mainWindow.webContents.send('update-available');
}
});
updater.start();
updater.check(function (err, results) {
if (err) {
return console.error(util.inspect(err));
}
console.log(results);
});
});
Do you guys see anything I could have forgotten/done wrong?
By reading the manual for npmrc (npm help npmrc), I have discovered the the .npmrc file is not unique. By configuring the registry the way I did, I only changed the per-user .npmrc. But there also should be such a file in your project root directory! It is in this one that you should configure the registry you want to use. Adding this file in project root directory solved the problem I was facing.
You should listen to error event.
Try this
updater.on('error', function (err) {
console.log(err);
});

Jasmine-node tests executed twice

My jasmine-node tests are executed twice.
I run those test from Grunt task and also from Jasmine command. Result is the same my tests are run twice.
My package.json :
{
"name": "test",
"version": "0.0.0",
"dependencies": {
"express": "4.x",
"mongodb": "~2.0"
},
"devDependencies": {
"grunt": "~0.4.5",
"grunt-jasmine-node":"~0.3.1 "
}
}
Here is my Gruntfile.js extract :
grunt.initConfig({
jasmine_node: {
options: {
forceExit: true,
match: '.',
matchall: true,
extensions: 'js',
specNameMatcher: 'spec'
},
all: ['test/']
}
});
grunt.loadNpmTasks('grunt-jasmine-node');
grunt.registerTask('jasmine', 'jasmine_node');
One of my test file :
describe("Configuration setup", function() {
it("should load local configurations", function(next) {
var config = require('../config')();
expect(config.mode).toBe('local');
next();
});
it("should load staging configurations", function(next) {
var config = require('../config')('staging');
expect(config.mode).toBe('staging');
next();
});
it("should load production configurations", function(next) {
var config = require('../config')('production');
expect(config.mode).toBe('production');
next();
});
});
I have 2 test files for 4 assertions
Here is my prompt :
grunt jasmine
Running "jasmine_node:all" (jasmine_node) task
........
Finished in 1.781 seconds
8 tests, 8 assertions, 0 failures, 0 skipped
Have you got any idea ?
All credit to 1.618. He answered the question here: grunt jasmine-node tests are running twice
This looks likes some buggy behaviour. The quick fix is to configure jasmine_node in your Gruntfile like this:
jasmine_node: {
options: {
forceExit: true,
host: 'http://localhost:' + port + '/',
match: '.',
matchall: false,
extensions: 'js',
specNameMatcher: '[sS]pec'
},
all: []
}
The key is the all parameter. The grunt plugin is looking for files with spec in the name. For some reason, it looks in the spec/ directory and everywhere else. If you specify the spec directory, its files get picked up twice. If you don't specify, it only gets set once, but then you can't put spec in any of your non-test filenames.

Resources