How to use the Google Closure Compiler to browserify your Node.js library - node.js

I have this simple Node.js library:
mylib/
|- inc.js
|- index.js
|- is_number.js
|- package.json
mylib/is_number.js
module.exports = x => typeof x === 'number';
mylib/inc.js
const is_number = require('./is_number');
module.exports = x => is_number(x) ? x + 1 : x;
mylib/index.js (value of the main property in my package.json)
module.exports = {
inc: require('./inc'),
utils: {
is_number: require('./is_number')
}
};
Example:
const mylib = require('mylib');
mylib.inc(41);
//=> 42
mylib.utils.is_number(42);
//=> true
How can I use the Google Closure Compiler to "browserify" my Node.js library so that it can work in a browser too? e.g.,
<script src="mylib/browser.min.js"></script>
<script>
const mylib = window.mylib;
mylib.inc(41);
//=> 42
mylib.utils.is_number(42);
//=> true
</script>

The canonical post for this answer is this Gist.
TL; DR
Create mylib/index_browser.js
window.mylib = {
inc: require('./inc'),
utils: {
is_number: require('./is_number')
}
};
Create mylib/externs.js
/** #externs */
var mylib;
var inc;
var utils;
var is_number;
Then:
$ cc --compilation_level ADVANCED \
--language_out ES5 \
--process_common_js_modules \
--module_resolution NODE \
--externs mylib/externs.js \
--isolation_mode IIFE \
--js mylib/index_browser.js mylib/inc.js mylib/is_number.js \
--js_output_file mylib/browser.min.js
Where cc is an alias to your Google Closure Compiler instance; see below for an example
Before we start:
I wrote this alias to make it easier to invoke the Google Closure Compiler (CC)
$ alias cc="java -jar /devtools/closure-compiler/compiler.jar"
$ cc --version
Closure Compiler (http://github.com/google/closure-compiler)
Version: v20210106
The browserified version of the library will be compiled down to ES5.
Step-by-step instructions
Your first attempt might look like this: just compile the exports file mylib/index.js
$ cc --compilation_level ADVANCED \
--language_out ES5 \
--js mylib/index.js
mylib/index.js:1:0: ERROR - [JSC_UNDEFINED_VARIABLE] variable module is undeclared
1| module.exports = {
^^^^^^
mylib/index.js:2:7: ERROR - [JSC_UNDEFINED_VARIABLE] variable require is undeclared
2| inc: require('./inc'),
^^^^^^^
2 error(s), 0 warning(s)
If CC doesn't know about module and require that's not a great start.
Fortunately we're only missing the --process_common_js_modules flag:
$ cc --compilation_level ADVANCED \
--language_out ES5 \
--process_common_js_modules \
--js mylib/index.js
mylib/index.js:2:7: ERROR - [JSC_JS_MODULE_LOAD_WARNING] Failed to load module "./inc"
2| inc: require('./inc'),
^
mylib/index.js:4:15: ERROR - [JSC_JS_MODULE_LOAD_WARNING] Failed to load module "./is_number"
4| is_number: require('./is_number')
^
2 error(s), 0 warning(s)
Still not great but this time the errors are different:
CC doesn't know which require you're talking about
CC doesn't know where these two other modules are
We need the --module_resolution flag and tell CC where the other modules are:
$ cc --compilation_level ADVANCED \
--language_out ES5 \
--process_common_js_modules \
--module_resolution NODE \
--js mylib/index.js mylib/inc.js mylib/is_number.js
However the output is empty...
Why? In ADVANCED compilation mode CC removes any code that is not used. Which is the case actually: so far all this stuff isn't used at all!
Let's check with a less aggressive compilation mode:
$ cc --compilation_level WHITESPACE_ONLY --formatting PRETTY_PRINT \
--language_out ES5 \
--process_common_js_modules \
--module_resolution NODE \
--js mylib/index.js mylib/inc.js mylib/is_number.js
var module$mylib$index = {default:{}};
module$mylib$index.default.inc = module$mylib$inc.default;
module$mylib$index.default.utils = {is_number:module$mylib$is_number.default};
var module$mylib$inc = {};
var is_number$$module$mylib$inc = module$mylib$is_number.default;
module$mylib$inc.default = function(x) {
return (0,module$mylib$is_number.default)(x) ? x + 1 : x;
};
var module$mylib$is_number = {};
module$mylib$is_number.default = function(x) {
return typeof x === "number";
};
We can see that even if the ADVANCED compilation mode didn't remove everything, this wouldn't be very useful anyway. Where is window.mylib for example?
The only way I managed to get both my library available at window.mylib and compiled with the most aggressive compilation mode, is to have a separate exports file for the browser.
From this mylib/index.js
module.exports = {
inc: require('./inc'),
utils: {
is_number: require('./is_number')
}
};
To this mylib/index_browser.js
window.mylib = {
inc: require('./inc'),
utils: {
is_number: require('./is_number')
}
};
When you add to the window object CC knows that this code may be reached so it can't safely remove it anymore.
Let's try again with this file:
$ cc --compilation_level ADVANCED --formatting PRETTY_PRINT \
--language_out ES5 \
--process_common_js_modules \
--module_resolution NODE \
--js mylib/index_browser.js mylib/inc.js mylib/is_number.js
function b(a) {
return "number" === typeof a;
}
;window.g = {h:function(a) {
return b(a) ? a + 1 : a;
}, j:{i:b}};
That is looking better but there is a major problem: CC has mangled all the names!
Don't worry! We only need to tell which names CC should leave alone. That is the purpose of an externs file.
mylib/externs.js
/** #externs */
var foo;
var inc;
var utils;
var is_number;
We need another flag: --externs
$ cc --compilation_level ADVANCED --formatting PRETTY_PRINT \
--language_out ES5 \
--process_common_js_modules \
--module_resolution NODE \
--externs mylib/externs.js \
--js mylib/index_browser.js mylib/inc.js mylib/is_number.js
function b(a) {
return "number" === typeof a;
}
;window.mylib = {inc:function(a) {
return b(a) ? a + 1 : a;
}, utils:{is_number:b}};
Getting there...
One obvious improvement is to wrap all of this in an IIFE to avoid polluting the global scope more than necessary.
We need the --isolation_mode flag:
$ cc --compilation_level ADVANCED --formatting PRETTY_PRINT \
--language_out ES5 \
--process_common_js_modules \
--module_resolution NODE \
--externs mylib/externs.js \
--isolation_mode IIFE \
--js mylib/index_browser.js mylib/inc.js mylib/is_number.js
(function(){function b(a) {
return "number" === typeof a;
}
;window.mylib = {inc:function(a) {
return b(a) ? a + 1 : a;
}, utils:{is_number:b}};
}).call(this);
Fantastic!
All that is left to do is save that into a file and remove the formatting to save up a few extra bytes:
$ cc --compilation_level ADVANCED \
--language_out ES5 \
--process_common_js_modules \
--module_resolution NODE \
--externs mylib/externs.js \
--isolation_mode IIFE \
--js mylib/index_browser.js mylib/inc.js mylib/is_number.js \
--js_output_file mylib/browser.min.js
mylib/browser.min.js
(function(){function b(a){return"number"===typeof a};window.mylib={inc:function(a){return b(a)?a+1:a},utils:{is_number:b}};}).call(this);

Related

How can I connect to Memgraph database and executes queries using Rust?

I'm starting to learn Rust. I want to try out connecting to the Memgraph database and executing a query. I'm running a local instance of Memgraph Platform in Docker. I'm running it with default settings.
Since you are using Docker right after you create a new Rust project using cargo new memgraph_rust --bin add the following line to the Cargo.toml file under the line [dependencies] :
rsmgclient = "1.0.0"
Then, add the following code to the src/main.rs file:
use rsmgclient::{ConnectParams, Connection, SSLMode};
fn main(){
// Parameters for connecting to database.
let connect_params = ConnectParams {
host: Some(String::from("172.17.0.2")),
sslmode: SSLMode::Disable,
..Default::default()
};
// Make a connection to the database.
let mut connection = match Connection::connect(&connect_params) {
Ok(c) => c,
Err(err) => panic!("{}", err)
};
// Execute a query.
let query = "CREATE (u:User {name: 'Alice'})-[:Likes]->(m:Software {name: 'Memgraph'}) RETURN u, m";
match connection.execute(query, None) {
Ok(columns) => println!("Columns: {}", columns.join(", ")),
Err(err) => panic!("{}", err)
};
// Fetch all query results.
match connection.fetchall() {
Ok(records) => {
for value in &records[0].values {
println!("{}", value);
}
},
Err(err) => panic!("{}", err)
};
// Commit any pending transaction to the database.
match connection.commit() {
Ok(()) => {},
Err(err) => panic!("{}", err)
};
}
Now, create a new file in the project root directory /memgraph_rust and name it Dockerfile:
# Set base image (host OS)
FROM rust:1.56
# Install CMake
RUN apt-get update && \
apt-get --yes install cmake
# Install mgclient
RUN apt-get install -y git cmake make gcc g++ libssl-dev clang && \
git clone https://github.com/memgraph/mgclient.git /mgclient && \
cd mgclient && \
git checkout 5ae69ea4774e9b525a2be0c9fc25fb83490f13bb && \
mkdir build && \
cd build && \
cmake .. && \
make && \
make install
# Set the working directory in the container
WORKDIR /code
# Copy the dependencies file to the working directory
COPY Cargo.toml .
# Copy the content of the local src directory to the working directory
RUN mkdir src
COPY src/ ./src
# Generate binary using the Rust compiler
RUN cargo build
# Command to run on container start
CMD [ "cargo", "run" ]
All that is now left is to get the address docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' CONTAINER_ID, create and image docker build -t memgraph_rust . and starting the application with docker run memgraph_rust.
If you ever decide to take your Rust program to an environment that doesn't have Docker you will maybe need to install rsmgclient driver
The complete documentation for connecting using Rust can be found at Rust quick start guide on the Memgraph site.

Uncaught TypeError: $ is not a function in core-js

I'm trying to install the BigCommerce Open Checkout script, and I'm currently getting this error when I try to run the basic installation locally:
Uncaught TypeError: $ is not a function
at eval (es.array.index-of.js?c975:15)
at Object../node_modules/core-js/modules/es.array.index-of.js
That file is:
'use strict';
var $ = require('../internals/export');
var $indexOf = require('../internals/array-includes').indexOf;
var arrayMethodIsStrict = require('../internals/array-method-is-strict');
var arrayMethodUsesToLength = require('../internals/array-method-uses-to-length');
var nativeIndexOf = [].indexOf;
var NEGATIVE_ZERO = !!nativeIndexOf && 1 / [1].indexOf(1, -0) < 0;
var STRICT_METHOD = arrayMethodIsStrict('indexOf');
var USES_TO_LENGTH = arrayMethodUsesToLength('indexOf', { ACCESSORS: true, 1: 0 });
// `Array.prototype.indexOf` method
// https://tc39.github.io/ecma262/#sec-array.prototype.indexof
$({ target: 'Array', proto: true, forced: NEGATIVE_ZERO || !STRICT_METHOD || !USES_TO_LENGTH }, {
indexOf: function indexOf(searchElement /* , fromIndex = 0 */) {
return NEGATIVE_ZERO
// convert -0 to +0
? nativeIndexOf.apply(this, arguments) || 0
: $indexOf(this, searchElement, arguments.length > 1 ? arguments[1] : undefined);
}
});
So far, I've tried updating core-js and NPM repeatedly with no luck.
core-js should not be compiled by Babel. When using webpack + babel to compile your code, you need to ensure that the webpack module rule for babel-loader excludes core-js.
Option 1
Tell webpack to not use babel-loader for any of the dependencies in your node_modules. Since core-js is a dependency in node_modules, this excludes core-js from being processed by babel.
// webpack.config.js
// This code snippet shows only the relevant part of the webpack config
module.exports = {
module: {
rules: [
{
test: /\.m?(j|t)sx?$/,
// Excluding node_modules means that core-js will not be compiled
exclude: /node_modules/,
use: ['babel-loader']
}
]
}
}
Option 2
Tell webpack to compile all dependencies with babel, except for the core-js dependency:
// webpack.config.js
// This code snippet shows only the relevant part of the webpack config
module.exports = {
module: {
rules: [
{
test: /\.m?(j|t)sx?$/,
// Compile all node_modules except core-js
include: {
and: [/node_modules/],
not: [/core-js/]
},
use: ['babel-loader']
}
]
}
}
Relevant Links
https://github.com/zloirock/core-js/issues/912
https://webpack.js.org/configuration/module/#ruleexclude
https://webpack.js.org/configuration/module/#ruleinclude
https://webpack.js.org/configuration/module/#rule-conditions

how to enable emmet in vim for ejs file

I wanna use emmet-vim on ejs files, my .vimrc config is
let g:user_emmet_install_global = 0
autocmd FileType html,css,ejs EmmetInstall
" redefine trigger key
let g:user_emmet_leader_key=','
let g:user_emmet_settings = {
\ 'php' : {
\ 'extends' : 'html',
\ 'filters' : 'c',
\ },
\ 'xml' : {
\ 'extends' : 'html',
\ },
\ 'haml' : {
\ 'extends' : 'html',
\ },
\ 'ejs' : {
\ 'extends' : 'html',
\ }}
yet it couldn't work, can anyone help?
P.S. my emmet-vim functions normally on html and css files
Maybe you can try it in this way with web-api
let g:user_emmet_settings = webapi#json#decode(join(readfile(expand('~/.snippets_custom.json')), "\n"))
Reference: emment-vim

How to insert the .env into a folder and run the nodemon?

SERVER.JS RESUME DOTENV
const dotenv = require('dotenv-safe');
this.dotenv = dotenv.load();
Problems:
1) I can not run the nodemon if it has only the .env file, it runs only if it contains the .env and .env.example files and I would like to know why and how to correctly match it.
2) How to insert the .env in the /env folder without the problem nodemon?
3) In my start script of package.json is the following "start_dev": "nodemon app/backend/src/start.js", however it is giving the following error:
nodemon app / backend / src / start.js
[nodemon] 1.18.9
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *. *
[nodemon] starting `node app / backend / src / start.js`
consign v0.1.6 Initialized in C: \ Users \ THIAGOSAAD \ Documents \ DEVELOPMENT \ NEORIS \ ALIANSCE \ aliansce-app-analyticals-panel
fs.js: 115
throw err;
^
Error: ENOENT: no such file or directory, open '.env.example'
at Object.openSync (fs.js: 436: 3)
at Object.readFileSync (fs.js: 341: 35)
C: \ Users \ THIAGOSAAD \ Documents \ DEVELOPMENT \ NEORIS \ ALIANSCE \ aliansce-app-analyticals-panel \ node_modules \ dotenv-safe \ index.js: 27: 45)
at new Application (C: \ Users \ THIAGOSAAD \ Documents \ DEVELOPMENT \ NEORIS \ ALIANSCE \ aliansce-app-analyticals-panel \ app \ backend \ src \ config \ server.js: 11: 32)
at-the-object. <anonymous> (C: \ Users \ THIAGOSAAD \ Documents \ DEVELOPMENT \ NEORIS \ ALIANSCE \ aliansce-app-analyticals-panel \ app \ backend \ src \ config \ server.js: 65: 18)
at Module._compile (internal / modules / cjs / loader.js: 688: 30)
at Object.Module._extensions..js (internal / modules / cjs / loader.js: 699: 10)
at Module.load (internal / modules / cjs / loader.js: 598: 32)
at tryModuleLoad (internal / modules / cjs / loader.js: 537: 12)
at Function.Module._load (internal / modules / cjs / loader.js: 529: 3)
at Module.require (internal / modules / cjs / loader.js: 636: 17)
at require (internal / modules / cjs / helpers.js: 20: 18)
at aliasce-app-analyticals-panel \ app \ backend \ src \ start.js: 1: 78)
at Module._compile (internal / modules / cjs / loader.js: 688: 30)
at Object.Module._extensions..js (internal / modules / cjs / loader.js: 699: 10)
at Module.load (internal / modules / cjs / loader.js: 598: 32)
[nodemon] app crashed - waiting for file changes before starting ...
And if I run the nodemon in the C:\Users\username\Documents\DEVELOPMENT\NEORIS\ ALIANSCE\aliansce-app-analyticals-panel\app\ ackend\src directory
It works!
I looked at this line of code - https://github.com/rolodato/dotenv-safe/blob/master/index.js#L27
It tries to read file .env.example but can not find it in the current folder (run pwd to check it)
It might be 3 ways to solve issue
1) Run
cd app/backend/src
nodemon start.js
2) Move files .env, .env.example to parent folder (aliansce-app-analyticals-panel) and then run nodemon app/backend/src/start.js
3) Do not use dotenv-safe at all. Use your own simple script like this one
Just look at this simple example:
https://github.com/olegdovger/pizza-delivery-api/blob/master/lib/env.js (script)
https://github.com/olegdovger/pizza-delivery-api/blob/master/index.js#L1 (how to invoke script)
With help of #OlegDover and yargs, I managed to pass .env file from a different path and use nodemon for hot-reloading during development.
e.g. $ nodemon --watch /path/to/.env server.js --envPath=path/to/.env will pick up changes to .env file and restart deployment.
Example Code
.env
EXAMPLE_HOST=myhost
EXAMPLE_PORT=5566
env.js
/*
* Module dependencies
*/
const fs = require("fs");
const yargs = require("yargs");
/*
* Custom class to update process.env from custom filepath
* Ref: https://github.com/olegdovger/pizza-delivery-api/blob/master/lib/env.js
*/
class Env {
constructor(envPath) {
this.variables = [];
this._setup(envPath);
}
_setup(envPath) {
try {
const data = fs.readFileSync(envPath, {
encoding: "utf-8",
});
const stringArray = data.split("\n");
this.variables = stringArray.map((string) => {
const arr = string.split("=");
return {
name: arr[0],
value: arr[1],
};
});
} catch (err) {
console.error("Unable to load .env;", err);
}
}
load() {
this.variables.forEach((variable) => {
process.env[variable.name] = variable.value;
});
}
}
/*
* Load .env from argv filepath
*/
const argv = yargs.argv;
new Env(argv["envPath"]).load();
/**
* Register
*/
module.exports = {
EXAMPLE_HOST: process.env.EXAMPLE_HOST || "localhost",
EXAMPLE_PORT: Number(process.env.EXAMPLE_PORT) || 12345,
};
server.js
const { EXAMPLE_HOST, EXAMPLE_PORT } = require("./env");
The environment variables can then be loaded/used in the project, having the fallback values if they are not defined in the .env file.
i.e. if EXAMPLE_HOST is not present in .env, this value will default to localhost

how to configuration vim-easytags for javascript

I want to use vim-easytags for javascript, so that it can use jsctags to generate tags each time I save my code. From the documentation of vim-easytags, I notice it supports javascript tags and jsctags. But how to set the configuration struggled me. Can anyone help me fix my .vimrc?
let g:easytags_python_enabled=1
let g:easytags_events = ['BufWritePost']
let b:easytags_auto_highlight = 1
let g:easytags_async=1
let g:easytags_by_filetype=1
let g:easytags_languages = {
\ 'javascript': {
\ 'cmd': 'jsctags',
\ 'args': ['-f'],
\ 'fileoutput_opt': '-f',
\ 'stdout_opt': '-f-',
\ 'recurse_flag': '-R'
\ }
\}
This seems to do it for me:
let g:easytags_languages = {
\ 'javascript': {
\ 'cmd': 'jsctags',
\ 'recurse_flag': ''
\ }
\}

Resources