JSPM System.import 404s - jspm

I am trying to learn JSPM as it seems like it is the future for installing client-side JavaScript. I am NOT attempting to use ES6 or TypeScript but am actually using CoffeeScript which I compile into 'standard' JavaScript for the browser. I am running node.js in express with my public files contained in ./public and accessible from the path /.
Having installed jspm my package.json configuration is:
"jspm": {
"directories": {
"baseURL": "public",
"packages": "public/lib"
}
}
It is configured like so:
System.config({
baseUrl: '/',
defaultJSExtensions: true,
transpiler: false,
paths: {}
});
With this setup I run: jspm install lodash which installs the package in public/lib/npm/lodash#4.5.1. In my application JavaScript I would expect to be able to run:
System.import('lodash');
and would expect that to return a Promise. However, I get a 404 on /lodash.js. So, in an effort to fix this I decided to use the explicit path to lodash: lib/npm/lodash#4.5.1/lodash. That seems to resolve the lodash 404 but then I get a 404 for /buffer.js and /process.js which I assume are dependencies of lodash.
Surely there has to be a better way than this? What am I missing here?! Part of the difficulty I am having is that most of the examples seem to use ES6 import directives which are irrelevant to me.

It seems that you are missing some paths on your systemjs config:
System.config({
baseURL: "/",
defaultJSExtensions: true,
transpiler: false,
paths: {
"github:*": "lib/github/*",
"npm:*": "lib/npm/*"
},
map: {
"lodash": "npm:lodash#4.6.1",
...
"npm:lodash#4.6.1": {
"buffer": "github:jspm/nodelibs-buffer#0.1.0",
"process": "github:jspm/nodelibs-process#0.1.2"
},
...
}
});
Also, you should have the lodash dependency declared on your package.json:
{
"jspm": {
"directories": {
"baseURL": "public",
"packages": "public/lib"
},
"dependencies": {
"lodash": "npm:lodash#^4.6.1"
}
}
}

Related

Using tsconfig-paths-webpack-plugin gives "Module not found" error for "fs" and other standard modules

I have spent half a day looking for a solution and trying everything I came across.
What I want is to use imports relative to my src folder by using an #src alias. Eg.
import { GmailMgr } from '#src/google-api/GmailMgr';
The most popular way to achieve this seems to be using https://www.npmjs.com/package/tsconfig-paths-webpack-plugin
Editing tsconfig.json like this makes vs code happy:
{
"compilerOptions": {
"outDir": "./dist/", // path to output directory
"sourceMap": true, // allow sourcemap support
"strictNullChecks": true, // enable strict null checks as a best practice
"module": "CommonJS", // specify module code generation
"jsx": "react", // use typescript to transpile jsx to js
"target": "es5", // specify ECMAScript target version
"allowJs": true, // allow a partial TypeScript and JavaScript codebase
"baseUrl": "./src",
"paths": {
"#src/*":["*"]
}
},
"include": [
"./src/"
]
}
To inform webpack about the paths in tsconfig.js, I then added the TsconfigPathsPlugin to webpack.config.js as described in the readme:
const path = require("path");
const webpack = require("webpack");
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
module.exports = {
entry: "./App.tsx",
context: path.resolve(__dirname, "src"),
mode: "development",
module: {
rules: [
{
test: /\.(t|j)sx?$/,
loader: 'ts-loader',
exclude: /node_modules/
},
{
enforce: "pre",
test: /\.js$/,
exclude: /node_modules/,
loader: "source-map-loader"
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
},
resolve: {
// changed from extensions: [".js", ".jsx"]
extensions: [".ts", ".tsx", ".js", ".jsx"],
alias: {
'react-dom': '#hot-loader/react-dom',
},
plugins: [new TsconfigPathsPlugin()]
},
output: {
path: path.resolve(__dirname, "dist/"),
publicPath: "/dist/",
filename: "bundle.js"
},
devServer: {
contentBase: path.join(__dirname, "public/"),
port: 45011,
publicPath: "http://localhost:45011/dist/",
hotOnly: true,
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
devtool: "source-map"
};
When I run webpack --mode production, I can see that the files that don't use node_modules but use this #src import style are compiled so it works but I use the google api packages in one file (GmailMgr.ts in the errors) and those rely on things like fs, child_process, net and tls and for each of them, I get an error like this:
ERROR in ../node_modules/https-proxy-agent/dist/agent.js
Module not found: Error: Can't resolve 'tls' in 'D:\MartijnFiles\Documents\Programming\0502-crew\youtube4me\node_modules\https-proxy-agent\dist'
# ../node_modules/https-proxy-agent/dist/agent.js 16:30-44
# ../node_modules/https-proxy-agent/dist/index.js
# ../node_modules/gaxios/build/src/gaxios.js
# ../node_modules/gaxios/build/src/index.js
# ../node_modules/google-auth-library/build/src/transporters.js
# ../node_modules/google-auth-library/build/src/index.js
# ./google-api/GmailMgr.ts
# ./components/YTNotifications.tsx
# ./App.tsx
It looks like it's trying to find fs, etc. inside the folder of the module instead of looking for it by starting in the node_modules root. If I remove the tsconfig-paths-webpack-plugin and paths, everything is fine but I have to stick to imports like import { GmailMgr } from '../../../google-api/GmailMgr';
P.S. I have tried webpack-node-externals and it works for the errors but this is for a website so I then get errors in the browser that require doesn't exist.
I encounter the same problem, but I don't think it's related to certain api.
I think it's a bug when using tsconfig-paths-webpack-plugin with webpack5.(I suppose you are using webpack5)
I submitted a issue here: https://github.com/dividab/tsconfig-paths-webpack-plugin/issues/60
It has started to dawn on me that webpack only has trouble with modules that require node to perform (eg. fs) and a browser won't be able to do. I suppose the google api modules are intended purely for backend (while you are able to use them perfectly if you include them using in the html). I guess I'll have to split my app into front and back end.
Update: I was right in this and split it up. However, I did still use webpack for both, just with different configs. In the backend webpack, I then used target: 'node' which prevents anything that should come from node_modules from being packed.
You may need to specify the full path to src/. Rather than using TsconfigPathsPlugin, I was able to resolve the issue by using the Webpack alias property in resolve, and using path.resolve(...) to my source directory.
In webpack.config.js:
resolve: {
extensions: [ '.ts', '.js' ],
alias: {
'#src': path.resolve( __dirname, 'src' )
},
},
For some reason using the full path worked, whereas using relative paths in webpack.config.js like #src: './src' did not. I suspect this is why TsconfigPathsPlugin didn't work as it was pulling the relative path from tsconfig.json.

electron-updater: Can not find module 'debug'

I am developing Desktop App(windows/mac) using Electronjs. I was trying to implement auto-update feature using electron-updater since I am using electron-builder for the building.
I am able to generate .exe file for my app but when trying to install, it's throwing an error: "Can not find module 'debug'". Please find attached screenshot.
Without electron-updater implementation, my app is running fine. When I am importing autoUpdator in my index.js, started getting that error. I am using autoUpdator as below:
const {autoUpdater} = require("electron-updater");
autoUpdater.on('update-downloaded', (ev, info) => {
setTimeout(function() {
autoUpdater.quitAndInstall();
}, 5000)
})
app.on('ready', ()=> {
autoUpdater.checkForUpdates();
});
Please find the libraries description below:
"electron-updater": "^4.0.6"
"electron": "^3.0.6"
"electron-builder": "^20.38.4"
I followed below links:
Electron builder Auto Update
electron builder using local server
I am new to the Electron js actively looking for your support.
As asked please find my build configuration below:
"build": {
"appId": "com.****.*****",
"productName": "********",
"directories": {
"output": "build"
},
"publish": [
{
"provider": "generic",
"url": "http://127.0.0.1:4080/"
}
],
"nsis": {
"oneClick": false,
"perMachine": true,
"allowElevation": true,
"allowToChangeInstallationDirectory": true,
"deleteAppDataOnUninstall": true,
"createDesktopShortcut": true
},
"win": {
"target": "nsis"
},
"files": [
"!**/.vscode",
"!**/build",
"!**/config",
"!**/assets/data",
"!**/src"
],
"extraResources": [
{
"from": "src/assets/data",
"to": "dist/assets/data",
"filter": "database*"
}
]
},
The line "!**/src" in your exclude list is the culprit.
Many node modules will have "src" folders which have to be packaged/bundled along with your application source code.
If you observe "debug" module folder under "node_modules" it has a "src" folder which has been excluded by above rule.
Suggestion: If you have your apps source folder as "src", rename it to something else like "source" (which is in your control), but ensure you don't exclude "src" folders of node_modules (renaming these is not in your control as it could break the module's integrity and they get overwritten on fresh npm install also)

Importing node modules with TypeScript, Angular 2 and SystemJS

I am writing a basic Angular 2 app. I am creating a class User that has a function validPassword() that uses bcrypt to validate a password:
import { compareSync, genSaltSync, hashSync } from 'bcrypt';
import { Document, Schema, model } from 'mongoose';
export class User {
username: string;
password: string;
isValidPassword(password: string): boolean {
return compareSync(password, this.password)
}
}
let userSchema = new Schema({
username: { required: true, type: String },
password: { required: true, type: String }
}, { timestamps: true });
userSchema.pre('save', function (next) {
this.password = hashSync(this.password, genSaltSync(8));
next();
});
export interface UserDocument extends User, Document {}
export const Users = model<UserDocument>('User', userSchema);
As you see, I am using the bcrypt and mongoose npm packages.
My SystemJS is configured as follows:
(function (global) {
System.config({
map: {
'#angular': 'node_modules/#angular',
'bcrypt': 'node_modules/bcrypt',
'bindings': 'node_modules/bindings',
'mongoose': 'node_modules/mongoose',
'rxjs': 'node_modules/rxjs'
},
paths: {
'node_modules/#angular/*': 'node_modules/#angular/*/bundles'
},
meta: {
'#angular/*': {'format': 'cjs'}
},
packages: {
'src': {main: 'main', defaultExtension: 'js'},
'#angular/core': {main: 'core.umd.min.js'},
'#angular/common': {main: 'common.umd.min.js'},
'#angular/compiler': {main: 'compiler.umd.min.js'},
'#angular/forms': {main: 'forms.umd.min.js'},
'#angular/http': {main: 'http.umd.min.js'},
'#angular/platform-browser': {main: 'platform-browser.umd.min.js'},
'#angular/platform-browser-dynamic': {main:'platform-browser-dynamic.umd.min.js'},
'bcrypt': {main: 'bCrypt.js'},
'mongoose': {main: 'index.js'},
'rxjs': {defaultExtension: 'js'}
}
});
}(this));
My typings dependencies are:
{
"globalDependencies": {
"bcrypt": "registry:dt/bcrypt#0.0.0+20160316155526",
"core-js": "registry:dt/core-js#0.0.0+20160914114559",
"jasmine": "registry:dt/jasmine#2.5.0+20161003201800",
"mongodb": "registry:dt/mongodb#2.1.0+20160602142941",
"mongoose": "registry:dt/mongoose#4.5.9+20161010180758",
"node": "registry:dt/node#6.0.0+20161014191813"
}
}
My tsconfig is as follows:
{
"compilerOptions": {
"baseUrl": ".",
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
}
}
When I go to run the project, the following errors display in the console:
1274 GET http://localhost:8080/crypto 404 (Not Found)
http://localhost:8080/node_modules/mongoose/lib.js 404 (Not Found)
http://localhost:8080/node_modules/bindings/ 404 (Not Found)
I understand this is a SystemJS issue. When I go to add, say,
'bindings': 'node_modules/bindings'
to the map object and,
'bindings': {main: 'bindings.js'},
to the packages object in SystemJS, I get a whole new set of errors (cannot find fs and path).
Should I be manually adding all missing package paths each time I install a new package? Is there a better way to do this?
I recently had the same issue when bundling my server-side into one file with SystemJS. The problem, at least with mongoose (and I suspect the others), is that SystemJS does not support node extension format so it doesn't understand to look for index.js inside the "./lib" folder. And even if you add "mongoose/lib" to your System.config, mongoose depends on a slew of node modules that would require an obnoxious amount of mapping in your System.config.package.mongoose to compensate.
A solution that I've found is to create a new System module and set it to the "package" that you need, above your System.config.
System.set('package', System.newModule({
default: require('package')
}));
Unfortunately if you're using typescript your import statements require your "package" to have a type. These are basically just a set of interfaces and abstract classes so that your entire typescript project can understand the "package" library has functions, classes, etc...
But some package types, like mongoose, do not have a default export. So if you set the mongoose module like above and import like below..
import mongoose from 'mongoose';
you are sure to get either transpiler or IDE typescript errors because as said above the typings type does not have a corresponding default export.
To fix this just set allowSyntheticDefaultImports option to true in your tsconfig.json
Hope this helps :)
I was stuck with the same problem for some time, and I was using Angular-cli so guess no SystemJs involved.
I was trying to load 'diff' node module, and following worked for me:
import * as JsDiff from 'diff';
Source: https://medium.com/#s_eschweiler/using-external-libraries-with-angular-2-87e06db8e5d1
Hope it helps!

Cannot find module "shelljs" on including the lib in angular 2 typescript

I want to include shelljs library to angular 2 typescript. I have included the shelljs.d.ts file to my node_modules/shelljs library.
My package.json
"name": "myproj1",
"description": "myproj1: A project",
"typings": {
"shelljs": {
"definitions": "node_modules/shelljs/shelljs.d.ts",
"source": "node_modules/shelljs/global.js"
}
},
My webpack.config.js
var path = require('path');
module.exports = {
entry: './app/web/boot.ts',
output: {
path: path.resolve(__dirname, "js"),
filename: "bundle.js"
},
resolve: {
extensions:['','.js','.ts']
},
module:{
loaders: [{
test: /\.ts/,
loaders: ['ts-loader'],
exclude: /node_modules/
}]
},
target: 'node'
};
My package.json compiler options:
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true
},
My TS file:
import child = require("shelljs");
somefun(){
child.exec('node --version',(code, stdout, stderr)=>{
console.log('Exit code:', code);
console.log('Program output:', stdout);
console.log('Program stderr:', stderr);
});
}
I am getting the error as "Cannot find module 'shelljs'". Please help me to include the library in my project.
Use tsd to manage all your typings.
From your project directory:
npm install tsd -g
tsd install node --save
tsd install shelljs --save
Then include the reference to shelljs in your foo.ts:
/// <reference path="typings/shelljs/shelljs.d.ts" />
import {exec} from "shelljs";
exec('node --version', code => {
console.log('Exit code:', code);
});
Based on the comments, here is the summary:
Using shelljs is only possible in NodeJS environment. This can be either raw nodejs instance, or some projects which contain nodejs in self, like Electron.
Also you should pay attention, which Module System you are using. For NodeJS you can use CommonJS without any further bundlers. But if you compile your TypeScripts for the frontend, where NodeJS is not present, then you should also bundle your CommonJS modules with browserify. Or you can use other types of Modules, like amd or SystemJS, and then in typescript compiler options, you set `"module": "system" for instance. See all options here

Getting started on minifying CSS/SCSS with Grunt?

After inheriting a project, I've found the developer was using SCSS and Grunt to Minify his code. I'm new to both, but noticed I had to install grunt-cli locally. I've done so and need to make some edits to the style sheets, but am still working through how to get the scss to minify after making changes.
The structure of the grunt/scss area is:
_ (root folder)
_/css
_/grunt
_/img
_/inc
_/img
_/js
_/misc
_/sass
Inside _/grunt is:
gruntfile.js
npm-debug.log
package.json
Steveax helped me figure our that I was missing the local grunt setup:
npm install
I've found the SCSS files inside the _/scss folder and am comfortable editing them for the purposes of updating styles; however, after saving one I've noticed that they don't automatically update the minified css in the _/css folder, and am left looking through the files and documentation for a solution. I think an experienced eye will know what command I've missed.
Here is an example of an scss file, _/sass/common.scss, I'd like to be able to save and replace the css equivalent, _/css/common.css
EDIT: Per the help of Robert Levy (below), it seems I just need to run Grunt after making changes.
(x-See edit above) Do I simply run uglify from the _ directory?
uglify /sass/common.scss -o /css/common.css -p 1
Inside of package.json is:
{
"name": "exampletheme.com",
"version": "0.1.0",
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-concat": "^0.3.0",
"grunt-contrib-uglify": "^0.4.0",
"grunt-contrib-imagemin": "^0.5.0",
"grunt-contrib-watch": "^0.6.0",
"grunt-contrib-compass": "^0.7.2",
"grunt-contrib-sass": "^0.7.3"
}
}
Inside of _/grunt/gruntfile.js is:
module.exports = function(grunt) {
// All configuration goes here
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
// Configuration for concatinating files goes here.
dist: {
src: [
'../js/libs/owl.carousel.js',
'../js/libs/jquery.actual.js',
'../js/libs/chosen.jquery.js',
'../js/libs/jquery.parallax.js',
'../js/src/common.js'
],
dest: '../js/pro/global.js',
},
},
uglify: {
build: {
src: '../js/pro/global.js',
dest: '../js/pro/global.min.js',
},
},
imagemin: {
dynamic: {
files: [{
expand: true,
cwd: '../img/src/',
src: ['**/*.{png,jpg,gif}'],
dest: '../img/pro/'
}]
}
},
compass: {
dev: {
options: {
sassDir: '../sass',
cssDir: '../css',
fontsDir: '../fonts',
imagesDir: '../img/',
images: '../img/',
javascriptsDir: '../js/pro',
//environment: 'development',
outputStyle: 'compressed',
relativeAssets: false,
httpPath: '.',
}
},
},
watch: {
scripts: {
files: ['../js/**/**.js'],
tasks: ['concat', 'uglify'],
options: {
spawn: false,
},
},
images: {
files: ['../img/src/**.{png,jpg,gif}'],
tasks: ['imagemin'],
options: {
spawn: false,
}
},
compass: {
files: ['../**/*.{scss,sass}'],
tasks: ['compass:dev'],
}
},
svgstore: {
defaults: {
options: {
prefix : 'icon-',
},
files: {
'../img/svg-defs.svg': ['../img/svg/*.svg']
}
}
},
});
// Where we tell Grunt we plan to use this plug-in.
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-imagemin');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-compass');
grunt.loadNpmTasks('grunt-svgstore');
// Where we tell Grunt what to do when we type "grunt" into the terminal.
grunt.registerTask('default', ['concat', 'uglify', /*'imagemin',*/ 'compass', 'svgstore', 'watch']);
};
just run grunt and it will invoke the default task which you can see in the last line of your gruntfile.js will in turn run concat, uglify, compass, svgstore, and watch.
compass is the one which is compiling the scss and minifying it.
the watch task is interesting because it tells grunt to continue running, keep an eye on your files, and recompile when things change.

Resources