Using Flow for browser apps - javascript

I want to use Flow (the static type checker for JavaScript by Facebook) for browser apps. How do you get Flow to follow the other .js files which are being used by a given .js file? In Node.js, the use of the require function makes Flow follow other modules and check for type errors, and I want a similar functionality for browser apps too.
Say I have a Classroom.js file which uses a module Student.js. When I run Flow, it will throw the error identifier Student Unknown global name.

Facebook uses browserify to do this in their Flux Chat example. Browserify inlines the require statements in node-style JavaScript to produce code that can be run in the browser.
Here are the relevant bits of their package.json:
{
"scripts": {
"build": "NODE_ENV=production browserify . | uglifyjs -cm > js/bundle.min.js",
},
"browserify": {
"transform": [
["reactify", { "stripTypes": true }],
"envify"
]
}
}

I have run into this problem myself, just now.
As you have a single, simple dependency (Classroom --> Student, this link contains a workaround that might help in your case. http://flowtype.org/docs/third-party.html
It says, create a new directory, put an "interface file" inside (this is basically a stub. pick any name for the file), and include everything with
flow check --lib /abs/path/to/my/interfacefiledir/ Classroom.js
For more complex scenarios, like secondary dependencies, third-party-libraries (like including jQuery with its full API), I don't have a strategy.
I think the facebook-flow team has put "add more interface files" on their to-do list. http://flowtype.org/docs/coming-soon.html#_

Related

Is "browser" field of package.json useless?

I recently do some search about front-end project management and get a confusion.
I notice that there is a field "browser" in package.json, but I don't know what role it plays.
In my opinion, we use package pack tool like Rollup to build .esm.js for browser, and in browser, just import the .esm.js file by <script> tag, we can't import any npm package in browser. So, I think field "browser" is useless.
For example:
Project structure:
packageA---
|--dist
|--main.esm.js
|--main.common.js
|--main.js
|--package.json
package.json:
{
"name": "packageA",
"main": "./dist/main.common.js",
"browser": "./dist/main.esm.js"
}
// this is a js file which use packageA.
// when we use Node to execute this file, will return "./dist/main.common.js".
const p = require("packageA")
Q: in browser, how to import packageA ? and who will follow the field "browser" and return "./dist/main.esm.js" to us?
Thanks a lot.
Perhaps you'd like to read the specification of the browser
field of package.json. Npm doesn't select platform-specific files directly, rather it's a hint to the bundler (such as webpack or rollup) about which files to use depending on whether it's bundling for the browser or for something else (e.g.: for Node.js).
This way, the same code can be used between node and browser platforms. When node requires the file, the default node-specific files are used, but when the bundler bundles it, the browser-specific files are used (substituted) instead.
-- That is hardly useless! --
Examples from the spec:
alternate main - basic
"browser": "./browser/specific/main.js"
replace specific files - advanced
"browser": {
"module-a": "./shims/module-a.js",
"./server/only.js": "./shims/client-only.js"
}

Can the Angular production build not shorten class names?

Is it possible to tell the Angular production build not to shorten class names?
Something like `ng serve -o --prod=true --abbreviateClassName=false
The issue I'm having is that I'm using this library:
https://github.com/fireflysemantics/validator/
It allows us to decorate class properties in order to validate them.
Since Angular shortens the class names I'm getting errors like this:
main.2876a5e2eb85f08784d9.js:1 Uncaught Error: The ValidationContainer
already contains context with signature t_e_sku.
at Function.t.addValidationContext
The decorators are keyed by ConstructorName_propertyName and since the Angular production build shortens the name this introduces conflicts when creating the validation contexts per the decorators.
You can try disabling optimization:
https://github.com/angular/angular-cli/wiki/build
ng serve --prod --optimization=false
There is also an optimization flag for the builder configuration in the angular.json file:
"architect": {
"build": {
"builder": "#angular-devkit/build-angular:browser",
"options": {
"optimization": false
I'm not exactly sure if this flag is the same as the above.
I'm sure this will increase the bundle sizes. There aren't any finer grain controls here for this sort of thing, and I don't think a custom builder will help.
We haven't had the ng eject option to create a custom WebPack build for a while, but you might find some online examples of how to do it manually. It'll be a pain to update when Angular 9 comes out.
Maybe this library you're using was intended for NodeJS and not web browsers.

Set up tests with Typescript and Ava : bad require

I'm setting up AVA with Typescript to tests my JS code. Internally, I'm first calling TSC to compile my files, then call AVA with babel-register to test them (Babel register allowing require to be resolved).
"ava": "tsc && ava testJs/**/*.spec.js"
testJs being the output folder of Ts. My problem is that, even thought everything pretty much work, I have this kind of statement, usually picked up by Webpack :
import "./index.page.css";
Webpack gently require it, but babel-register doesn't. I had to change the behavior to accept .css file as noop. Here is the issue : because I'm using tsc as a compiler, those files are not copied at all in testJs, meaning they are not available in the first place.
I wanted to know what would be the best way to solve this, as I think copy-pasting the whole folder (to have all files available) just to execute tests is a bit of an overkill. Especially since, if I suddenly import a .json file (for example)I will have new problems.
For example, is there a way to tell babel-register to ignore require it cant resolve instead of breaking ?
Thanks !
You can use ignore-styles to ignore certain types of requires. By default it ignores all kinds of CSS and images (full list) and you can customise it to ignore other extensions as well.
You simply require it before babel-register in your AVA config.

Enable code completion for node_modules in WebStorm

I'm new to WebStorm, and fairly new to Node development. I am working on an existing project, and want to have code completion for my node_modules. More specifically, I'm using Chai and WebStorm doesn't seem to find the .have member of my expect.to statement.
This is my code, simplified:
var expect = require('chai').expect;
import {Customer} from '../../app/model/Customer.js';
describe('...', function() {
it('...', function() {
var customer = new Customer();
expect(customer).to.have.property('name');
});
});
I get squiggly lines under the have call, and WebStorm tells me Unresolved variable have.
If I F12 on the to, WebStorm takes me to another node module, shelljs, but I haven't imported that one.
Is this because WebStorm can't resolve everything in javascript?
I've enabled Coding Assistance for NodeJS as per the docs, but that made no difference.
Problem is caused by weird dynamic way these chai methods are defined. As a workaround I can suggest using chai.d.ts:
Open "Settings | Languages & Frameworks | JavaScript | Libraries"
Click "Download..." button and select "TypeScript community stubs"
Find "chai" and click "Download and Install".
See http://blog.jetbrains.com/webstorm/2014/07/how-webstorm-works-completion-for-javascript-libraries/, 'Using TypeScript community stubs (TypeScript definition files)' for more information
WebStorm 2020.1
TypeScript definitions can also be added directly via package.json:
Open the project's package.json
Position the cursor on the package (within the dependencies section)
Press alt+enter (or click the light bulb)
Choose Install '#types/name' (where name is the dependency)
For example:
In WebStorm 2019.3, here are the steps I follow to force Code Completion (including auto-import) to work for a custom, self-published NPM package that contains pure ES6 modules only:
Ensure that the project, itself, has a package.json file at the root of the project, and that package.json includes the desire package in the "dependency" object. For example:
{
"name": "testproject",
"version": "1.0.0",
"dependencies": {
"#yourname/yourpackage": "latest"
}
}
In WebStorm, select File > Invalidate Caches / Restart...
To enable auto-import for package contents, ensure that the JavaScript file in which the package is being used has AT LEAST ONE export statement. For example, in the following code, an export is present, so Code Completion auto-imports the package function isNil():
export function init () {
isNil
}
By comparison, the following code does not contain an export statement, so isNil() is not automatically imported:
function init () {
isNil
}
For me, all three of the preceding steps are necessary for Code Completion to work for my own NPM packages (with pure ES6 modules) in WebStorm.

How can I minify an ExtJs 5 project without Sencha?

I have been researching the ability to minify an ExtJS application without Sencha and the closest I have come to is this link:
Is there a way to minify an ExtJS application without Sencha CMD?
However, I am not sure how to execute the file in one of the later comments. I am using the minify-maven-plugin with com.samaxes.maven and the CLOSURE engine. I was able to generate the minified js file of the entire project but I get errors when I try to load the web page.
I was able to verify the web page was calling the correct file. I received the error "TypeError: q is undefined"...not helpful at all. Without the minified file, the web application runs perfectly. So, the generated minified file must have something wrong with it.
The suggestion at the bottom of the link above indicates the sequence of files that I should include but I have no idea how to actually implement this. Also, there are probably over a hundred javascript files that need to be minified so I would rather not have to type each file in the jsb file.
Are there any suggestions on how to minify my entire project at build time with maven?
I'm using Grunt to build the project, but it doesn't really matter as all you need is to combine files, so maven should be more than capable.
I wanted my dev version to still rely on Extjs dynamic class loader so I don't have to rebuild the project whenever I modify one file, and only production version to be minified into a single file. There were a few pitfalls before I got it working, here is what I ended up with. Also this is for ExtJS6, but it probably still should be the same.
It is all controlled by backend variable dev, which when set to false will use minified sources.
index.html (I'm using some meta templating language as example)
<html>
<head>
{{if dev}}
<script src="/ext/ext-all-debug.js"></script>
{{else}}
<script src="/ext/ext-all.js"></script>
{{/if}}
<script>
var dev = {{dev}};
Ext.Loader.setConfig({enabled: dev});
</script>
{{if dev}}
<script src="/app.min.js"></script>
{{else}}
<script src="/app.js"></script>
{{/if}}
</head>
<body></body>
<html>
app files, requires directive doesn't work well when the dynamic loader is disabled, so I had to add conditions like this everywhere:
Ext.define('MyApp.view.Panel', {
extend: 'MyApp.view.GenericPanel',
requires: dev ? [
'MyApp.view.AnotherView',
] : [],
...
});
Gruntfile.js (if you need only concatenation replace uglify with concat everywhere)
module.exports = function(grunt) {
grunt.initConfig({
pkg : grunt.file.readJSON('package.json'),
uglify : {
build: {
files: {
'../app.min.js': ['../app/view/GenericPanel.js', '../app/**/*.js', '../app.js'],
}
}
},
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.registerTask('default', [ 'uglify' ]);
};
grunt's project.json:
{
"name": "My App",
"version": "1.0.0",
"devDependencies": {
"grunt": "~0.4.5",
"grunt-contrib-concat": "^1.0.1",
"grunt-contrib-uglify": "^1.0.1"
}
}
The order of files matter, by default grunt will use alphabetic order. If you extend some class, the parent class has to be included higher. app.js should be at the end. Other than that it is working well in a single mixed file, so I didn't have to customize the file order further. Grunt has pretty powerful path patterns, so if you need to make sure some file is included first you just list it before other path patterns and it will be smart enough to not include it twice.
I recommend you start with simple concatenation without minification, and only if that works try minifying it. When minifying you might need to be careful with global functions and variables as they can be renamed if minifier is too aggressive. Grunt's minifier almost worked for me with the default settings, I just had to made couple small changes to my code (related to global functions).
While I am not sure why you would want this, the main thing you need is the so-called dependency tree - which tells you the order in which to include the source files.
Then you can put all the files (ExtJS source, libraries if applicable and also your own views) into one big file, in the correct order. This file should then work exactly as the 500 distinct files. (It did for me.)
That done, you can search for a working minifier. Not every minifier can minify ExtJS code, and I don't remember my last results before we finally decided to switch to Sencha Cmd, but I think Microsoft Javascript Minifier was one that worked for us.
Apart from that, minified JavaScript is really legible. You should provide the source of the error, with 200 characters before and 200 characters after the error, and I guess someone here can tell what's going on there.

Categories

Resources