Flow: Ignore non-JS requires like `require('image!Kitten')`

Created on 28 Mar 2015  路  28Comments  路  Source: facebook/flow

Most helpful comment

@sibelius Instead of matching the whole module name, you can use extension matcher as suggested in previous posts. This works for me:

Change:

module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'

To:

module.name_mapper.extension='\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)' -> 'RelativeImageStub'

All 28 comments

cc @amasad, perhaps the packager could autogenerate a Flow interface definition for the image files it fines.

@jeffmo is working on this, I think. We want to add a rule to flowconfig to redirect certain require patterns to a predefined mock.

Super. Looking forward to that.

Thanks for the ping. I'm currently focused on building out 'import type'/'export type' -- but I will begin working on this module-path redirection stuff right after that.

:+1: also very interested in this

+1

I think this is for Webpack users, if I've inferred correctly.

It's for anyone using the require.js spec's extensions incl RN.

Ok. Makes sense.

Update: https://github.com/facebook/flow/commit/625c25ae5d7c429cf4f7191bc3a8e948623d271d just landed which adds a config option of the form:

[options]
module_name.name_mapper = 'regexp-pattern' -> 'replacement-pattern'

(This should go out to opam/brew/etc with the next release)

When using Flow with it's [default] "node" module system, the mapper that wins is the first mapper whose regexp pattern matches _and_ whose generated replacement results in module identifier string that represents an actual/known module in the system.

For anyone who happens to use the "haste" module system, due to the way Flow lazily matches haste module definitions to module imports/requires, the config option isn't able to consider whether a replacement candidate is a valid module at the time the conversion happens -- so the haste module system will use the first mapper whose regexp string matches.

The regexp string is just passed directly to ocaml's built-in regexp utilities, so that can serve as the reference for various supported regexp tokens and replacement templates:

http://caml.inria.fr/pub/docs/manual-ocaml/libref/Str.html#VALregexp

This is terrific @jeffmo.

@amasad - is an image source mock in the works?

@jeffmo: can replacement-pattern generate a relative module name?

@ide: Should be pretty simple. Just making this object a module: https://github.com/facebook/react-native/blob/master/packager/react-packager/src/Packager/index.js#L178-L186
I'll do it once I understand how the replacement-pattern works.

@amasad: Sure. It's a string match that happens just before the lookup, so the result of running the replacement should be the same as if you put the replacement directly into the code

@jeffmo could you please provide an example of how module_name.name_mapper can actually be used, for the not so savvy? How to do a sass import, how to do an image import, etc.
thank you!

@thealjey - there are a couple tests checked in to exercise module.name_mapper. You can search for them.

Taking the first example that, shows

module.name_mapper='1Doesnt\(Exist\)' -> '\1s'

This means it will treat require('1DoesntExist) as require('Exists'). Each test is a folder with a tiny little Flow world inside. So The config_module_name_rewrite_node test is making sure this works for node module systems. In that directory there is a file Exists.js which is being required via the various renames and A.js which tests out the feature.

Is there any way to simply ignore all imports of e.g. .sass files without implementing a mock of some sort?

backing up what @jedwards1211 said - it's a little cumbersome as is.

for instance, in my use case, i'm using webpack and css modules and i'm pulling in local yaml and local css like so:

import fields from '../_fields.yaml'
import classes from './reference.css'

// react down here

understandably , both of those imports throw flow errors

screen shot 2016-04-13 at 5 48 44 pm

pretend both of those files are in the screenshot

Looking up how to deal with this issue leads me to this url, and the flow docs

When I attempt to use the solution mentioned in the docs

module.name_mapper.extension= 'css' -> '<PROJECT_ROOT>/CSSFlowStub.js.flow'

I get this error (was mapper.extension removed?):

screen shot 2016-04-13 at 5 51 46 pm

i also tried the other doc example, the non shorthand approach, and while it doesn't error out, it also doesn't appear to do anything

for instance, I would expect this to throw a flow error:

// my undeclared, potentially null/undefined require
import classes from './myClasses.css'

// react down here
return <div className={classes.div} />

But it doesnt

So, yeah. The only way I can think to handle my particular case is to declare every single local require manually in my interface file, or use a flow ignore comment (which is what I currently do) or to manually re-assign and type all my non js imports like below

// this works, but still requires manually declaring in my interface file
const classes: Object = require('./reference.css')

// react
return <div className={classes.div} />

Is there an official way to handle non js / local imports? Or should I just continue to use require for those files? It just seems really tedious to manually declare and type every single non js asset

edit: forgot to mention my flow version. i'm on 0.22.1

@rossPatton , pulling an example from the react-native codebase:
https://github.com/facebook/react-native/blob/master/.flowconfig
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'

Where this is the implementation of RelativeImageStub:
https://github.com/facebook/react-native/blob/master/Libraries/Image/RelativeImageStub.js

Since Flow loads all modules and uses that @providesModule, you could stick it anywhere in your code tree.

like @AlexanderTserkovniy said this linked helped.

This is what I ended up with:

In your .flowconfig:

[options]
module.name_mapper.extension='css' -> '<PROJECT_ROOT>/flow/extension-resolver.js.flow'
module.name_mapper.extension='vue' -> '<PROJECT_ROOT>/flow/extension-resolver.js.flow'

In flow/extension-resolver.js:

/* @flow */
declare export default { [key: string]: string }
// example usage
import Main from 'main.vue';

I still have to explicitly specify the file extension when importing but it works good enough for now.

I using this on my .flowconfig

module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'

but flow keeps complaining about Require module not found

@sibelius Instead of matching the whole module name, you can use extension matcher as suggested in previous posts. This works for me:

Change:

module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'

To:

module.name_mapper.extension='\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)' -> 'RelativeImageStub'

Do we have to reset some cache or something maybe? I have never seen any of these things work. Just tried a bunch of stuff on a new project again, and again with no luck unfortunately. Using 0.53.1.

module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
module.name_mapper.extension='png' -> 'RelativeImageStub'
Error: src/screens/Screens.js:25
 25:       icon: require('App/src/assets/images/tabbar-x.png'),
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ App/src/assets/images/tabbar-x.png. Required module not found
$ ls src/assets/images/tabbar-x*png
src/assets/images/[email protected]

Requiring images of kittens should always be allowed 馃樃

@jslz @sibelius Are you using react-native? RelativeImageStub is a module exported by that project, so if you don't have it then that's why flow can't find it. Personally, I used that regex, and then created a stub module manually for it. In the root of my project, I have a file called libdefs.js:

declare module 'RelativeImageStub' { declare module.exports: string }

Then, the relevant portion of my .flowconfig:

[libs]
libdefs.js

[options]
module.name_mapper.extension='\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)' -> 'RelativeImageStub'

This got rid of Required module not found on requiring images for me. [email protected]

this one worked for me https://github.com/facebook/flow/issues/345#issuecomment-319647394

in the latest version of flow

@mikaello It works for me. Thanks!

All of this actually didn't work for me. Btw I also have

[untyped]
.*/node_modules/react-native
Was this page helpful?
0 / 5 - 0 ratings