How to tell systemjs to ignore an import - node.js

This is for the systemjs library, not systemjs-builder
I might have a bit of an edge case here. But I'm trying to setup my frontend web application to run it's unit tests in the command line. My setup currently builds the typescript to the systemjs register format and loads is imported into the site as per their specifications. The issue I am currently facing is that one of my dependencies reflect-metadata has a node auto detect system that makes a require('crypto') call, which is a native node module (not available in npm). The error I am receiving is:
Error: ENOENT: no such file or directory, open '/Users/path/to/project/node_modules/crypto.js'
There are lots of things at play here I understand, but the behavior I am after is for systemjs to completely ignore the require('crypto') call and allow it to pass through completely unchanged as node will correctly load this at runtime.
Due to the multi-module enterprise application we are creating I don't really have the freedom to export the typescript to commonjs due to sub-dependencies receiving the Systemjs version rather then a temp commonjs build. (The only way to do this would be to include the commonjs version in our private npm dist build, which is far from ideal)
Here is the current config I am using for system as I have been attempting to get system to ignore the crypto library require. I've left this in the exact state it was when the above error was generated, comments and all so you could see what I've tried.
System.config({
defaultJSExtensions: true,
map: {
'angular2': 'node_modules/angular2',
'reflect-metadata': 'node_modules/reflect-metadata/Reflect',
'crypto': 'node_modules/crypto'
}
// packages: {
// 'reflect-metadata': {
// format: 'global',
// exports: 'Reflect',
// defaultExtension: false,
// meta: {
// '*': {
// defaultExtension: false
// }
// }
// }
// }
// meta:{
// 'reflect-metadata/Reflect':{
// format: 'global',
// exports: 'Reflect',
// defaultExtension: false
// }
// }
});

To ignore a require you can map it to the #empty module within your SystemJS config file.
you can do this by by adding System.config({ map: { 'crypto': '#empty' } })

Related

Is there a way to use Vite with HMR and still generate the files in the /dist folder?

First of all, I wanna say that I've started using Vite awhile ago and I'm no Vite expert in any shape or form.
Now, about my problem: I'm working on a Chrome Extension which requires me to have the files generated in the /dist folder. That works excellent using vite build. But, if I try to use only vite (to get the benefits of HMR), no files get generated in the /dist folder. So I have no way to load the Chrome Extension.
If anyone has faced similar issues, or knows a config that I've overlooked, feel free to share it here.
Thanks!
With this small plugin you will get a build after each hot module reload event :
In a file hot-build.ts :
/**
* Custom Hot Reloading Plugin
* Start `vite build` on Hot Module Reload
*/
import { build } from 'vite'
export default function HotBuild() {
let bundling = false
const hmrBuild = async () => {
bundling = true
await build({'build': { outDir: './hot-dist'}}) // <--- you can give a custom config here or remove it to use default options
};
return {
name: 'hot-build',
enforce: "pre",
// HMR
handleHotUpdate({ file, server }) {
if (!bundling) {
console.log(`hot vite build starting...`)
hmrBuild()
.then(() => {
bundling = false
console.log(`hot vite build finished`)
})
}
return []
}
}
}
then in vite.config.js :
import HotBuild from './hot-build'
// vite config
{
plugins: [
HotBuild()
],
}

Rollup - incorrect path resolution

I want to use the library ebnf from NPM and create a bundle using rollup. Since the ebnf is installed to node_modules I also use the rollup plugin rollup-plugin-node-resolve.
The problem is that ebnf contains the code require('..') which - in my case - is resolved to dist in my case. Thus it seems .. is interpreted relative to the output file instead of being relative to the source file.
This is my rollup.config.js (taken from my test repo jneuendorf/rollup-broken-resolve):
import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'cjs'
},
// name: 'MyModule',
plugins: [
resolve(),
commonjs(),
]
}
Is this a problem in rollup-plugin-node-resolve or am I doing something wrong?
Since some of the external libraries needed will still be available only as Common.js modules, you could also convert them to ES-Modules:
"Since most packages in your node_modules folder are probably legacy CommonJS rather than JavaScript modules, you may need to use rollup-plugin-commonjs"
https://github.com/rollup/rollup-plugin-commonjs
"Convert CommonJS modules to ES6, so they can be included in a Rollup bundle"
Just in case someone searching this issue on how to make #rollup/plugin-node-resolve (previously was rollup-plugin-node-resolve) to work with relative path. I just found the solution:
function resolve(file, origin) {
// Your way to resolve local include path
}
function pathResolve(options) {
return {
resolveId: function(file, origin) {
// Your local include path must either starts with `./` or `../`
if (file.startsWith('./') || file.startsWith('../')) {
// Return an absolute include path
return resolve(file, origin);
}
return null; // Continue to the next plugins!
}
};
}
Here is how to combine it with #rollup/plugin-node-resolve:
import {nodeResolve} from '#rollup/plugin-node-resolve';
function pathResolve(options) { /* ... */ }
export default {
// ...
plugins: [pathResolve(), nodeResolve()]
};

I don't understand how to work Bower properly

I'm building a site and I've decided to use a bootstrap template for the back-end (admin tools and whatnot).
I like the look of sb-admin-2 (http://startbootstrap.com/template-overviews/sb-admin-2/) but I'ma bit confused how to practically employ this in my site.
I installed Bower and installed sb-admin using bower install startbootstrap-sb-admin-2
Now I have a folder called bower_components, and it's filled with all the relevant packages... However, these packages include the development files as well.
If I upload this to my site as is, 80% of it will be unnecessary source data.
I'm currently using Gulp with my project, but I don't yet see how the 2 are supposed to interact. Is there a gulp package for compiling the bower_components into 1 concise thing?
I'm new to this kind of workflow and I can't find the answers to the questions despite my efforts. Apologies if I sound like a total noob.
There's no pre-built gulp package that will pull in all your bower source files. You should write a task that pulls in just the files you need. Here's an example from a project I'm working on (simplified):
var scripts = [
'bower_components/timezone-js/src/date.js', // https://github.com/mde/timezone-js
'bower_components/jquery/jquery.min.js', // http://api.jquery.com/
'bower_components/jquery-migrate/jquery-migrate.js', // https://github.com/appleboy/jquery-migrate
'bower_components/jquery-ui/ui/minified/jquery-ui.min.js', // todo: include just the bits we need
'bower_components/jqueryui-touch-punch/jquery.ui.touch-punch.min.js', // https://github.com/furf/jquery-ui-touch-punch
'bower_components/jquery-cookie/jquery.cookie.js', // https://github.com/carhartl/jquery-cookie
'bower_components/jquery.expander/jquery.expander.min.js', // https://github.com/kswedberg/jquery-expander
'bower_components/jquery.transit/jquery.transit.js', // http://ricostacruz.com/jquery.transit/
'bower_components/select2/select2.min.js', // http://ivaynberg.github.io/select2/
'bower_components/fancybox/source/jquery.fancybox.pack.js', // http://fancyapps.com/fancybox/
'bower_components/lodash/dist/lodash.compat.min.js', // https://lodash.com/docs
'bower_components/underscore.string/dist/underscore.string.min.js', // https://github.com/epeli/underscore.string#string-functions
'bower_components/json2/json2.js', // https://github.com/douglascrockford/JSON-js
'bower_components/jquery-validation/dist/jquery.validate.min.js', // http://jqueryvalidation.org/documentation/
'bower_components/jquery-file-upload/js/jquery.iframe-transport.js',
'bower_components/jquery-file-upload/js/jquery.fileupload.js', // https://blueimp.github.io/jQuery-File-Upload/
'bower_components/DataTables/media/js/jquery.dataTables.js', // https://datatables.net/
];
gulp.task('scripts', function () {
return gulp.src(scripts, {base: '.'})
.pipe(plumber())
.pipe(sourcemaps.init({
loadMaps: false,
debug: debug,
}))
.pipe(concat('all_the_things.js', {
newLine:'\n;' // the newline is needed in case the file ends with a line comment, the semi-colon is needed if the last statement wasn't terminated
}))
.pipe(uglify({
output: { // http://lisperator.net/uglifyjs/codegen
beautify: debug,
comments: debug ? true : /^!|\b(copyright|license)\b|#(preserve|license|cc_on)\b/i,
},
compress: { // http://lisperator.net/uglifyjs/compress, http://davidwalsh.name/compress-uglify
sequences: !debug,
booleans: !debug,
conditionals: !debug,
hoist_funs: false,
hoist_vars: debug,
warnings: debug,
},
mangle: !debug,
outSourceMap: true,
basePath: 'www',
sourceRoot: '/'
}))
.pipe(sourcemaps.write('.', {
includeContent: true,
sourceRoot: '/',
}))
.pipe(plumber.stop())
.pipe(gulp.dest('www/js'))
});
I'm cherry-picking the source files I want, combining and minifying them, and dumping them into my public directory so that can be served to the client. You don't need to upload the bower_components folder to your production server; but it probably wouldn't hurt much either (it's not THAT big!).

How do you setup a require.js config with typescript?

Ok, I've been reading a lot of questions and answers about this, and a lot of it is rubbish.
I have a very simple question. How do I do the equivalent of this:
require.config({
paths: {
"blah": '/libs/blah/blah',
}
});
require(['blah'], function(b) {
console.log(b);
});
In typescript?
This doesn't work:
declare var require;
require.config({
paths: {
"blah": '/libs/blah/blah',
}
});
import b = require('blah');
console.log(b);
s.ts(8,1): error TS2071: Unable to resolve external module ''blah''.
s.ts(8,1): error TS2072: Module cannot be aliased to a non-module type.
error TS5037: Cannot compile external modules unless the '--module' flag is provided.
Compiling with the --module flag, with a dummy blah.ts shim compiles, but the output is:
define(["require", "exports", 'blah'], function(require, exports, b) {
require.config({
paths: {
"blah": '/libs/blah/blah'
}
});
console.log(b);
});
Looks like it might work, but actually no, the require.config is inside the require block, it is set after it is already needed.
SO! I've ended up so far with this as a solution:
class RequireJS {
private _r:any = window['require'];
public config(config:any):void {
this._r['config'](config);
}
public require(reqs:string[], callback:any):void {
this._r(reqs, callback);
}
}
var rjs = new RequireJS();
rjs.config({
paths: {
"jquery": '/libs/jquery/jquery',
"slider": '/js/blah/slider'
}
});
rjs.require(['slider'], function(slider) {
console.log(slider);
});
Which seems terrible.
So be clear, inside modules that depend on each other, this sort of thing works perfectly fine:
import $ = require('jquery');
export module blah {
...
}
I just need a proper way to setting the requirejs config at a top level, so that the imported paths for the various named modules are correct.
(...and this is because, largely, 3rd party dependencies are resolved using bower, and installed in the /lib/blah, where as the shim files I have for their definitions are in src/deps/blah.d.ts, so the default import paths are incorrect after moving the generated modules files into /js/ on the site)
NB. I've mentioned jquery here, but the problem is not that jquery doesn't work property as an AMD module; I have a shim jquery.ts.d file for this. The issue here is the requirejs paths.
Yesterday I wrote up a solution to this exact issue on my blog - http://edcourtenay.co.uk/musings-of-an-idiot/2014/11/26/typescript-requirejs-and-jquery:
TL;DR - create a config file config.ts that looks something like:
requirejs.config({
paths: {
"jquery": "Scripts/jquery-2.1.1"
}
});
require(["app"]);
and ensure your RequireJS entry point points to the new config file:
<script src="Scripts/require.js" data-main="config"></script>
You can now use the $ namespace from within your TypeScript files by simply using
import $ = require("jquery")
Hope this helps
This post is 3 years old, and there's a lot of changes that have been made when using Typescript. Anyway, after some search on the web,some research on TS documentation-these guys made some good job, I found something that could help.
so this can apply to the latest current of TS (2.2.1)
you probably know that you can use
npm install --save #types/jquery
do the same for your 3rd party JS librairies such as require
now you need to define what your TypeScript Compiler has to do, and how, so create a tsconfig.json file that contains:
// tsconfig.json file
{
"compilerOptions": {
"allowJs": true,
"baseUrl": "./Scripts",//Same as require.config
"module": "amd",
"moduleResolution": "Node",//to consider node_modules/#types folders
"noImplicitAny": false,
"target": "es5", // or whatever you want
"watch": true
}
now, let's focus on require's configuration
// require-config.ts
declare var require: any;
require.config({
baseUrl: "./Scripts/",
paths: {
"jquery": "vendor/jquery/jquery.x.y.z"
// add here all the paths your want
// personnally, I just add all the 3rd party JS librairies I used
// do not forget the shims with dependencies if needed...
}
});
so far so good
now focus on your module written in TS that would use jquery and that is located in Scripts/Module folder:
// module/blah.ts
/// <amd-module name="module/blah" />
import $ = require("jquery");
export function doSomething(){
console.log("jQuery version :", $.version);
}
So this answer looks the same as Ed Courtenay's, doesn't it?
and user210757 mentioned that it does NOT work!!!
and it does not! if you type in your console tsc -w --traceResolution, you'll see that tsc cannot find any definition for jquery.
Here's how to alleviate assuming you previously launch npm install --save #types/jquery by doing this, in a folder named node_modules\#types, you should get the TS definition for jquery
select the package.json file in jquery subfolder
look for the "main" property
set it to "jquery", the same as the alias you are using in your require.config
and done! your module would be transpiled as
define("module/blah", ["require", "exports", "jquery"], function (require, exports, $) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function doSomething() {
console.log("jQuery version:", $.fn.jQuery);
}
exports.doSomething = doSomething;
});
and that JS code looks good to me!
I just don't like the fact that our module dependencies list "require" & "exports", that sounds like a TS issue, but anyway IT WORKS!
if you want to use import for javascript modules you need to tell typescript about it so,
declare var require;
require.config({
paths: {
"blah": '/libs/blah/blah',
}
});
// Important, place in an external.d.ts:
declare module 'blah'{
// your opportunity to give typescript more information about this js file
// for now just stick with "any"
var mainobj:any;
export = mainobj;
}
import b = require('blah');
console.log(b);
alternatively you could simply do:
var b = require('blah'); and it should work as well

Correct way of loading non-AMD compatible jQuery plugins in require.js with jQuery in noConflict mode?

Say I want to use jquery together with a standard, non-amd enabled jquery plugin that has been defined using standard closure: (function($))( $.fn.myplugin = { ... } )(jQuery); and it all sits inside of a js/libs/jquery/jquery.myplugin.js.
I use this config:
require.config({
baseUrl: 'js/',
paths: {
'jquery': 'libs/jquery/jquery-noconflict',
'underscore': 'libs/underscore/underscore',
'backbone': 'libs/backbone/backbone',
'jquery-myplugin': 'libs/jquery/jquery.myplugin'
},
shim: {
'backbone': {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
'jquery-myplugin': {
deps: ['jquery']
}
});
I load jQuery in no-conflict mode in libs/jquery/jquery-noconflict.js, becase I don't want to pollute global namespace:
define(['libs/jquery'], function () {
return jQuery.noConflict(true);
});
and this is how I load my main app.js:
define([
'jquery',
'underscore',
'backbone',
'jquery-myplugin'],
function($, _, Backbone, MyPlugin){
//MyPlugin is always undefined, not even sure if
//I should be passing it here if it only extends jQuery?
});
Now, here is the problem I am experiencing - while I can use all libraries defined above without any problems, I could not work out the correct shim configuration to load non-AMD enabled jquery plugins.
I've tried setting up jquery-myplugin as deps of the jquery (and other way around) but I could never get it working.
It seems like I'm having problem with the following scenario:
jQuery loads in no-conflict mode.
plugin code runs, extending the instance of the jQuery above
I can use $ within my application, extended by the plugin code, so $.myplugin is available.
I have seen similar questions floating around but none of them actually resolves this issue giving only vague suggestions such as "use shim config"...
Edit
I also tried using
"jquery-myplugin": {
deps: ["jquery"],
exports: "jQuery.fn.myplugin"
}
And whilst plugin methods are available once loaded as AMD module this way, I still can't access: $('.class').myplugin() as default $ object hasn't been extended with myplugin code.
Using jQuery.noConflict(true) removes the jQuery global variable. When your plugin loads, it tries to access jQuery, but can't, causing this failure.
If your plugin was a module, it could get access to jQuery as a dependency. Or you could leave jQuery available as a global.
First, insure that "path/to/jquery-myplugin" actually extends window.jQuery and not $
noConflict() leaves window.jQuery object defined but unbinds itself from window.$ On some new browsers window.$ is built in alias for native document.querySelectorAll function.
Second, your myplugin does NOT need to return itself, as it cannot be used by itself. Since it extends jQuery, return jQuery from myplugin call.
Lastly, "path/to/jquery-myplugin" is NOT a module. It's a plain JS file. It's possible RequireJS tries to load it like a module and does not find define() call, which leads to mess. Try actually adding ".js" file extension to the reference to signal to RequireJS that it needs to use "js!" plugin to load the resource.
require.config({
paths: {
"jquery": "path/to/jquery",
"jquery-myplugin": "path/to/jquery-myplugin.js"
},
shim: {
"jquery": {
init: function() {
return window.jQuery.noConflict();
},
"jquery-myplugin": {
deps: ['jquery']
init: function($) {
return $;
},
}
}
});
I had the same problem as you today. Here is how I could fix it :
requirejs.config({
"baseUrl": "js/lib",
"paths": {
"app": "../app"
}
});
// Final version of jQuery with all needed plugins.
define("jquery", ["jquery-core", "myplugin"], function(jqCore) {
return jqCore;
});
// Define core jQuery module.
define("jquery-core", ["jquery-1.9.1.min"], function() {
return jQuery.noConflict(true);
});
// This module exposes jquery module to the global scope and returns previous defined version.
define("jq-global", ["jquery-core"], function(jqCore) {
var tmp = jQuery;
jQuery = jqCore;
return tmp;
});
// Define your plugin here, and don't forget to reset previous jQuery version.
define("myplugin", ["jq-global", "jquery.myplugin"], function(jqGlobal, jqPlugin) {
jQuery = jqGlobal;
});
// Load the main app module to start the app
requirejs(["app/main"]);
Now in my app/main.js file I can do the following :
define(["jquery"], function($) {
$('body').myplugin();
});
The idea here is to expose jQuery temporary before plugin code is executed. So far I didn't test the solution in a larger environment with a lot more modules to load, so I can't guarantee it will work in the long term ;)
Edit
This solution won't work!! Since requirejs doesn't load the scripts sequentially, it is possible the plugin js file loads before jquery which will cause the execution to fail. Sorry for this.
If someone has another idea...

Resources