Flow and module keyword stripping - module

To get the Flow type-checker to work with multiple files you need to import and export modules, but the basic setup with Babel does not erase the module keywords, leading to browser problems like
SyntaxError: export declarations may only appear at top level of a module
and
SyntaxError: import declarations may only appear at top level of a module
What's the proposed solution to this?
My babelrc:
{
"plugins": [
"transform-flow-strip-types"
]
}
The Javascript source
export class MyClass {}
gets transformed to the exact same.
Wanted output is
class MyClass {}

The transform-flow-strip-types plugin only removes Flow syntax extensions, but import/export is part of the ES2015 spec. To compile those as well, you need to add some more plugins. preset-es2015 will include these by default or you can use one of the babel-plugin-transform-es2015-modules-* plugins. Hope this helps!

Related

sass-loader additionalData/prependData/data bloats bundle size

I'm using Vue2 and laravel-mix and I want to have my variables accessible globally. I eventually found this:
mix.webpackConfig({
module: {
rules: [
{
test: /\.scss$/,
use: [
{
loader: 'sass-loader',
options: {
//this might be "data" or "prependData" depening on your version
additionalData: `#import "./resources/js/styles/variables.scss";`
}
}
]
}
]
}
})
This does make my variables globally accessible, but essentially copies the variables.scss into every single vue component, which massively bloats my bundle size.
How can I prevent this?
Edit: This only is an issue, when the imported file is relatively big. In my project, the imported file itsself imported a theme scss (to get access to the themes variables), which ultimately copied this whole thing everywhere I needed the variables.
I fixed this by defining my custom variables in a seperate file and using those variables in the "overwriting-variables" file, something like this:
custom-variables.scss
$red: #ff0000;
overwriting-variables.scss
import 'theme.scss'; //this bloated my project
import 'custom-variables';
$--theme-red: $red
And when I needed this theme color in my vue components I just imported the custom-variables.scss instead of overwriting-variables.scss.
This does fix my bloating issue, but doesn't fully solve the problem, I still have multiple instances of the custom-variables.scss in my project, it just doesn't matter because its really small. So I'd be still happy to hear about other solutions!
You need to separate your functions, variables & mixins from actual CSS rules.
These files will be imported and available to every component you write, which is great for things like variables, functions, or mixins, but you should avoid any actual CSS rules. Adding CSS rules to your shared Sass files will import those rules into every component and bloat your project. For global CSS rules, create a separate file and import it into your main App.vue file instead.
Source: https://austingil.com/global-sass-vue-project/

Can't import Ink interpreter with Javascript interpreter with Vue.js

I need to make a Vue.js site with a JavaScript Ink interpreter. The only one that seems to be production-ready is Ink.js. There are two ways to import it. One is in its TypeScript format, but my Vue setup does not use TypeScript. I could add it, maybe, although I'm not sure I want to. If I import the TypeScript libraries from Yarn, no matter which object I import, it shows up with a value of undefined in my code.
Then there is a pure es5 script available, that seems to be a transpiled version of the first one, but when I try to import that one, I get this error, I think from Babel:
Uncaught SyntaxError: Unexpected token '!'
cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/Ink.vue?vue&type=script&lang=js&:39 Uncaught SyntaxError: Unexpected token '!'
at Object../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/Ink.vue?vue&type=script&lang=js& (app.js:962)
My guess is that Babel is set up for es6 or es7 and the pure is5 file brings up some unexpected syntax. I tried to change babel.config.js, but I've found no option that's kept Vue.js from complaining. What am I doing wrong? 
After many failed attempts, I went around the problem in the following way: I imported the Story object directly from the library:
import { Story } from '../../node_modules/inkjs/engine/Story';
// ...
let story = new Story(storyText);
I know it's not what the documentation recommends, but it works. And it seems everything else that needs to be imported is, because when I try to read story.currentChoices I get an array of Choice objects that are in turn perfectly readable.
So this works for me. If anyone else runs into this problem, I'm not saying it's the right solution, I'm just saying that's what I finally ended up doing.

How does module path resolution work for functions in react native library?

I've noticed that files inside the react-native/Libraries can be imported without specifying the full path.
Like,
const EdgeInsetsPropType = require('react-native/Libraries/StyleSheet/EdgeInsetsPropType');
Is the same as,
const EdgeInsetsPropType = require('EdgeInsetsPropType');
How does this work?
In the case of the EdgeInsetsPropType module, those should be the same thing. The reason that you can import that module directly by its name is because of this line.
The #providesModule EdgeInsetsPropType comment is what makes it so you can import it directly. Here is a good basic explanation of why #providesModule works the way it does.
The packager uses two methods to look up modules. The first is based
on docblock headers: if you write "#providesModule X" in the first
docblock this enables require('X'). The other method is Node's
resolution.
This description was taken from this comment on Github.

Why do ambient declarations use namespace and module?

I noticed that many ambient declaration files declare a namespace and a module that merely exports the namespace, usually using some gymnastics that I don't really understand. For example, in react.d.ts you see this:
declare namespace __React {
... entire API of the react library ...
}
declare module "react" {
export = __React;
}
Why both a namespace and a module? Why not just declare the module with the library API inside it?
Why is the namespace called __React and not simply React? That seems like a rather awkward "don't use me" name, yet IntelliJ IDEA has imported this all over my source code and it seems to work.
This pattern is used to support UMD libraries.
These libraries generally put something into the global scope if they're loaded through a <script ...> tag, but return something to a module loader if invoked via a module system like RequireJS, CommonJS, or SystemJS.
In TypeScript, this means that if you import the module called 'react', you should get the same type as if you reference the global identifier React.
Most definition files simply write their .d.ts files such that the module shape and the global variable are always both present; the React authors didn't like that you could accidently refer to the global React if you were using a module loader (in which case the global wouldn't actually be there) so they separated out the declaration into __React, a separate .d.ts file that declared a global called React, and a module declaration for "react".

Confused by the way TypeScript uses "require(...)"

I've tried reading several blog posts but TypeScript modules still have me totally confused. In particular, I have used 3 different modules (all installed via npm) and each seems to show totally different behaviour:
(1) I can import and use Angular 2 from npm like this in my .ts:
import {bootstrap, Component, Directive, CORE_DIRECTIVES, FORM_DIRECTIVES} from 'angular2/angular2';
Then in my html I have:
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
This has the following results:
The TypeScript compiler knows to look for the angular2.d.ts file under node_modules, even though I just said "angular2/angular2"
The TypeScript compiler adds "var angular2_1 = require('angular2/angular2'); to the output JavaScript
The browser does not attempt to load the angular 2 JavaScript again despite the presence of the require, it somehow knows it's already loaded it via "angular2.dev.js" in the script tag
(2) The npm D3 module does not have a typescript definition, but I can download the one from DefinitelyTyped and then use it by putting:
/// <reference path="../../typings/tsd.d.ts" />
at the top of my .ts. and
<script src="../node_modules/d3/d3.js"></script>
in my html. It seems that being an old-style module it doesn't need an import statement, and as long as I leave it here the output JavaScript works fine. If I do try to use an import statement immediately after the reference line:
import * as d3 from 'd3';
then as with Angular2 it now adds:
var d3 = require('d3');
to the output JavaScript. However, unlike with the Angular case it doesn't realise it's already loaded the JavaScript via the script tag, and so the browser tries and fails to load a file simply called "d3" from the same directory as the html file, which fails.
(3) The npm Phaser module does include a .d.ts file, in a "typescript" subdirectory of the npm module. This is an old style module ("declare module Phaser"), so it seems I need not use "import.." syntax but instead just:
/// <reference path="../node_modules/phaser/typescript/phaser.d.ts"/>
at the top of my .ts file, as with the D3 example. The TypeScript compiler is happy, but unlike with the D3 example, under some circumstances (I haven't worked out quite what yet, doesn't seem to always happen) it outputs:
var phaser_1 = require('phaser');
in the JavaScript even when I haven't used an import statement. I'm not even using commonjs/requirejs in my phaser project, so "require" isn't even defined, causing failure.
And for completeness, unlike with either the Angular or D3 example, if I try putting an import statement after the reference line:
import * as Phaser from 'Phaser';
even the TypeScript compiler isn't happy. Perhaps in the D3 example the TypeScript compiler is treating the tsd.json or typings folder from DefinitelyTyped in special way, or maybe there is some other reason the import compiles for D3 but not for Phaser.
I have all sorts of questions:
1) What determines whether the TypeScript compiler includes a "require(...)" line in the output JavaScript?
2) Under what circumstances does the TypeScript compiler know where to find an external module in "npm_modules" when using "import", with or without needing a reference line at the top of the file?
3) Under what circumstances does the TypeScript compiler know where to find an ambient module in "typings" when using "import", with or without a "reference" line at the top of the file?
4) Under what circumstances does the TypeScript compiler know where to find an ambient module in "npm_modules" when using "import", with or without a "reference" line at the top of the file??
5) Maybe a commonjs/requirejs question rather than a typescript question, but if the TypeScript compiler does output a "require" line in the JavaScript, what do you do if the source of the JavaScript module is not set up with ES6 module exports?
1 ) I can import and use Angular 2 from npm like this in my .ts:
This is because
angular2 ships with its .d.ts file
The browser doesn't attempt to read require because of magic in angular2.dev.js
The npm D3 module fails && the phaser module fails at runtime
They don't have the magic you get from angular2.dev.js. Use something like webpack or browserify to provide this magic.
Unlike with either the Angular or D3 example, if I try putting an import statement after the reference line: import * as Phaser from 'Phaser';
This is because of how Phaser definition is declared. Apprarently it is missing declare module "Phaser" which is what is provided with d3 see here and angular.