How to prevent TypeScript from interrupting Webpack building on unresolved variables declared on Webpack's ProvidePlugin?
Asked Answered
F

4

9

Is there a way to prevent WebPack's building process from failing after typescript compiler start yelling on unresolved variables that actually are already configured on webpack's ProvidePlugin configuration?

webpack.config.js

plugins: [
...
new webpack.ProvidePlugin({
            $: "jquery",
            jQuery: "jquery",
            "window.jQuery": "jquery",
            "_": "underscore",
            "underscore": "underscore"
            //'process.env.NODE_ENV': '"development"'
        }),

]

tsconfig.json

{
  "compilerOptions": {


    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false,
    "suppressImplicitAnyIndexErrors": true,
    "declaration": false
  },
  "exclude": [
    "node_modules",
    "typings/main",
    "typings/main.d.ts"
  ]
}

https://webpack.github.io/docs/list-of-plugins.html#provideplugin

From my experience, the typescript is not aware of which variables will be injected into the module and as result the build is not completed.

This is the output of the build

ERROR in ./src/file1.component.ts
(77,9): error TS2304: Cannot find name '$'.

ERROR in ./src/file2.component.ts
(78,13): error TS2304: Cannot find name '$'.

ERROR in ./src/file3.ts
(155,15): error TS2304: Cannot find name 'jQuery'.

ERROR in ./src/file4.ts
(108,9): error TS2304: Cannot find name '$'.
Fullrigged answered 22/6, 2016 at 16:46 Comment(0)
N
1

If I understand ProvidePlugin correctly you still need to have declared jQuery and underscore as modules (externals or alias).

Therefore I'd recommend to load those modules in TypeScript with:

import * as $ from 'jquery';
import * as _ from 'underscore';

Then you just need to provide definition (.d.ts) files for those libraries. I recommend typings for that purpose.

typings install jquery --global
typings install underscore --global

I assume you are using ts-loader which would handle that automatically.

If you want to avoid import statements you can still declare those libraries with definitions from typings.

Or you can create your own simplified declaration:

declare var jQuery: any;
declare var $: any;
Notch answered 23/6, 2016 at 17:7 Comment(0)
O
7

I'm not fully satisfied with ahz's answer as I don't like to install typings globally or declare jQuery as any loosing all typechecking.

The solution that worked for me is to create global.d.ts with following content:

import * as _jQuery from 'jquery';

declare global {
  const jQuery: typeof _jQuery;
  const $: typeof _jQuery;
}

After that tsc passes without any warnings like Cannot find name '$'..

Found here.

Ornamental answered 23/10, 2018 at 14:46 Comment(0)
N
1

If I understand ProvidePlugin correctly you still need to have declared jQuery and underscore as modules (externals or alias).

Therefore I'd recommend to load those modules in TypeScript with:

import * as $ from 'jquery';
import * as _ from 'underscore';

Then you just need to provide definition (.d.ts) files for those libraries. I recommend typings for that purpose.

typings install jquery --global
typings install underscore --global

I assume you are using ts-loader which would handle that automatically.

If you want to avoid import statements you can still declare those libraries with definitions from typings.

Or you can create your own simplified declaration:

declare var jQuery: any;
declare var $: any;
Notch answered 23/6, 2016 at 17:7 Comment(0)
P
0

I'm gonna add to the top answer, by saying there's some exceptions, and here's how to solve them. I ran with this problem using Ant-Design and Redux.

When you use this:

import _Fake from 'fake-lib'

declare global {
  const Fake: typeof _Fake
}

It works, but only for libraries that have been exported as a namespace (Like React). In this case, you can safely do this:

const x: Fake.Property // GOOD: Fake acts as a namespace
Fact.Function          // GOOD: Fake acts a concrete type that contains Function

On the other hand, I had libraries that did not export as namespace (Like Redux) and caused this:

const x: Fake.Property // FAIL: Fake is not a namespace
Fact.Function          // GOOD: Fake acts a concrete type that contains Function

To circumvent this issue, you can essentially globally-augment the library to be treated as a namespace export, like so:

Modify your tsconfig.json to add the new hacks

"compilerOptions": {
    ...
},
"include": [
    "./src/**/*",
    "./types/**/*"
]

And add a types/fake.d.ts file containing

import * as Fake from 'fake-library'

export as namespace Fake
export = Fake

With these changes done now the global const declaration will work properly.

Pork answered 27/10, 2020 at 21:13 Comment(0)
U
-1

Don't babel-loader with ts-loader(remove this one!) upon babel 7! I hope this will save someone debugging in the future! Reference

Unsightly answered 25/3, 2022 at 4:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.