Skip to content
This repository has been archived by the owner on Jan 26, 2019. It is now read-only.

Cant import regular js files when using create-react-app-typescript #120

Closed
mhgamework opened this issue Jul 27, 2017 · 10 comments
Closed

Comments

@mhgamework
Copy link

I have some .js + .d.ts files which i am using in my create-react-app-typescript project. Everything works and runs fine with npm run start or npm run build.

When running npm run test, the import statements for these .js files return the name of the file, instead of actually importing the file.

I believe this behaviour is caused by the configuration line in "createJestConfig.js". The matches all .js files and replaces them with stubs:

'^(?!.*\\.(css|json)$)': resolve('config/jest/fileTransform.js'),

When adding .js to the ignored transform patterns, the tests correctly import my .js+.d.ts files

  transformIgnorePatterns: [
      '[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$',
      '^.+\\.js$' // I ADDED THIS LINE
    ],

I believe this is a bug/oversight in the configuration, since using .js+.dts files as source code is not that strange. In any case i do not think it makes sense to replace all .js files with stubs.
I would love to see this fixed in the project or a way to configure this without the massive workaround i have posted below

Thanks,
MH

PS

I use this workaround to prevent changing the react-scripts ts:

var Module = require('module');
Module.prototype.require = new Proxy(Module.prototype.require, {
    apply(target, thisArg, argumentsList){

        let name = argumentsList[0];

        if (name === "./utils/createJestConfig") {///\.\/utils\/createJestConfig/g.test(name)){
            var ret = Reflect.apply(target, thisArg, argumentsList);
            var ori = ret;
            createJestConfig = function (a, b, c) {
                var ret = ori(a, b, c);
                ret.transformIgnorePatterns.push('^.+\\.js$');
                return ret;
            }
            return createJestConfig;
        }
        else
            return Reflect.apply(target, thisArg, argumentsList)
    }
})

require("react-scripts-ts/scripts/test");
@DorianGrey
Copy link
Collaborator

Hm... yes, this is a catch-all clause to cover all files not matching the already listed ones.
The base version does this as well, i.e. everything that is not js/jsx/css/json will end up with the file transformer:
https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/scripts/utils/createJestConfig.js#L36

I agree that it should be possible to use .js files along with corresponding definitions, though I'm not sure about the advantage over using ts directly (maybe legacy code?).
However, I'm not sure if it's favorable to simply ignore .js files for transforming, or let them be transformed by babel-jest (since it's a direct dependency of jest, it's already installed, thus ...). It should be quite easy to pick up the solution from the CRA-main repo.

@wmonk , what do you think?

@mhgamework
Copy link
Author

I use js+dts in conjuction with protobufjs, which generates code and corresponding typings. I suppose this usecase falls under the category of reusing existing javascript libraries which are not written in typescript.

Since js+dts Does work for node_modules, it could make sense to not support JS for the package source code.
However, more generically the problem seems to be that i cannot create a "module/package" of my generated code and treat it like a node_module. Round-tripping the generated code to a npm repository and installing it will only make the problem bigger.

@DorianGrey
Copy link
Collaborator

The vast majority of "using existing javascript libraries not written in typescript" is covered by modules installed from external sources like the npm repository (so it would be located in node_modules). So it is still somewhat special, though reasonable to import existing (in your case: generated) code from ts.

Technically, it's not possible for a transformer to separate between "js files that still have to be transformed" and "js files that may be left as is" with acceptable effort. It is possible to configure this manually as long as there are paths or names to separate these, but it would require ejecting your project to add these capabilities.
As a result, I'd say there are two ways to achieve the support of js files, which both have advantages and disadvantages:

  1. Modify the "cover all" clause to not match .js files: '^(?!.*\\.(css|js|json)$)': resolve('config/jest/fileTransform.js').

    • Advantage: Simple solution.
    • Disadvantage: Would block transformation by babel, in case it is required.
  2. Add an additional entry to use babel-jest: '^.+\\.(js|jsx)$': 'babel-jest'.

    • Advantage: Would enable transformation of js files, in case it is required.
    • Disadvantage: Useless overhead in case no transformation is required.

(1) should be able to cover your case, but might be too simple for others, while (2) should be able to cover almost every case, but is a bit overkill for simpler ones like yours.

@mhgamework
Copy link
Author

I would prefer a way to to this without ejecting, but i understand that it is difficult to add this as default behaviour.
If there would be a way to add a decorator to the "createJestConfig" function, so i can add/adjust the corresponding configuration cleanly. This would also solve this problem for others using js+dts files.

@wmonk
Copy link
Owner

wmonk commented Aug 7, 2017

I don't really want to deviate from the react-scripts project, and think adding this feature would make tracking the origin project more difficult.

@wmonk wmonk closed this as completed Aug 7, 2017
@quantuminformation
Copy link

quantuminformation commented Nov 28, 2017

Has anyone managed this in a CRAT friendly way? I want to use https://devexpress.github.io/devextreme-reactive/react/grid/ but there are no typings yet.

@mhgamework
Copy link
Author

I ended up creating a proxy around node.require to fix create-react-app-ts from not supporting plain js files.

I injectthe proxy before running the regular react-scripts-ts/scripts/test. The proxy adds the necessary config to the createJestConfig file.

var Module = require('module');
Module.prototype.require = new Proxy(Module.prototype.require, {
    apply(target, thisArg, argumentsList){

        let name = argumentsList[0];

        if (name === "./utils/createJestConfig") {///\.\/utils\/createJestConfig/g.test(name)){
            var ret = Reflect.apply(target, thisArg, argumentsList);
            var ori = ret;
            createJestConfig = function (a, b, c) {
                var ret = ori(a, b, c);
                ret.transformIgnorePatterns.push('^.+\\.js$');
                return ret;
            }
            return createJestConfig;
        }
        else
            return Reflect.apply(target, thisArg, argumentsList)
    }
})

require("react-scripts-ts/scripts/test");

Then in package.json i use the following script

"test": "node custom-react-scripts-ts-test.js --env=jsdom",

Its possible you might need to add some npm packages for the proxy but i dont remember if that was the case or not

@quantuminformation
Copy link

quantuminformation commented Dec 1, 2017

Thanks for that, but I'm not really want to scare my fellow devs with that.) In any case, I want to include javascript files in my regular project, not just the test stuff.

@quantuminformation
Copy link

I'm trying to use pretender (js only) with typescript without the types by importing this way:

let Pretender:any = require('pretender')

image

If I just run it as normal it comes out like:

image

this might be a webpack issue, any ideas?

@wmonk
Copy link
Owner

wmonk commented Dec 12, 2017

You probably want to use require('pretender').default

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants