Why can't Webpack find a module if the TypeScript compiler is down?

I am trying to use Fuse in my TypeScript applications. I import module identifiers with import * as fuselib from 'fuse.js'; . This compiles with tsc . The problem I am facing is when I create a project using webpack --config config/webpack.prod.js --progress --profile --bail .

I get the Cannot find module 'fuse.js' . Fuse can be found here . Looking at my compiled JS, I cannot find the word fuse.js , so I assume that Webpack distorts the name. I tried to ignore the fuse.js keyword in UglifyJsPlugin , but that didn't help.

My Webpack configuration is pretty standard.

webpack.prod.js

 var webpack = require('webpack'); var webpackMerge = require('webpack-merge'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var commonConfig = require('./webpack.common.js'); var helpers = require('./helpers'); const ENV = process.env.NODE_ENV = process.env.ENV = 'production'; module.exports = webpackMerge(commonConfig, { devtool: 'source-map', output: { path: helpers.root('dist'), publicPath: '/', filename: '[name].[hash].js', chunkFilename: '[id].[hash].chunk.js' }, htmlLoader: { minimize: false // workaround for ng2 }, plugins: [ new webpack.NoErrorsPlugin(), new webpack.optimize.DedupePlugin(), new webpack.optimize.UglifyJsPlugin({ // https://github.com/angular/angular/issues/10618 mangle: { keep_fnames: true, except: ['fuse.js'] } }), new ExtractTextPlugin('[name].[hash].css'), new webpack.DefinePlugin({ 'process.env': { 'ENV': JSON.stringify(ENV) } }) ] }); 

webpack.common.js

 var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var helpers = require('./helpers'); module.exports = { entry: { 'polyfills': './src/polyfills.ts', 'vendor': './src/vendor.ts', 'app': './src/main.ts' }, resolve: { extensions: ['', '.js', '.ts', '.tsx'], modulesDirectories: ['src', 'node_modules'] }, module: { loaders: [ { test: /\.ts$/, loaders: ['awesome-typescript-loader', 'angular2-template-loader', 'angular2-router-loader'] }, { test: /\.html$/, loader: 'html' }, { test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/, loader: 'file?name=assets/[name].[hash].[ext]' }, { test: /\.css$/, exclude: helpers.root('src', 'app'), loader: ExtractTextPlugin.extract('style', 'css?sourceMap') }, { test: /\.css$/, include: helpers.root('src', 'app'), loader: 'raw' } ] }, plugins: [ // for materialize-css new webpack.ProvidePlugin({ "window.jQuery": "jquery", "window._": "lodash", _: "lodash" }), new webpack.optimize.CommonsChunkPlugin({ name: ['app', 'vendor', 'polyfills'] }), new HtmlWebpackPlugin({ template: 'src/index.html' }) ] }; 

What am I missing so that Webpack can see the fuse.js module?

+6
source share
2 answers

Update

I wrote new declarations for the library question based on this answer. Everything should work fine with the latest version, since they come with the library.

Answer

OK, that's what happens and why.

First, Fuze/index.d.ts tries to declare itself a global and external Fuze/index.d.ts in, but does it wrong. This leads to misuse, for example, to what led to your mistake almost inevitably.

It contains a module declaration containing a class declaration, presumably for the purpose of describing the form of the module, but the class is not exported.

 declare module 'fuse.js' { class Fuze // missing one of: export, export =, export default } 

This means that I cannot import the module correctly, and in fact there is a type error when trying to import a value and / or type from it.

Further in Fuse/index.d.ts he declares a global

 declare const Fuse; 

Presumably, based on conventions and reading comments in real JavaScript, this should take the same form as exporting from a module. Unfortunately, it has type any , which is not the same type as the trying module, because it is not valid, and not the type of the Fuse class, which is inside the specified module but not exported ...

So why the error? You probably have one of the following programs: import fuse; import fuse; import * as a fuse;

after which you should use Fuse as

 const myFuse = new Fuse(); 

This will cause a TypeScript value to be selected to represent the Fuse Fuse runtime view for the runtime so that you can use the value imported from the module.

To fix the problem, you can use the global const Fuse , and not import it anywhere. Unfortunately, this is not what is intended. The author almost certainly had in mind the following contents of Fuze/index.d.ts :

 export = Fuse; export as namespace Fuse; declare class Fuse { constructor(list: any[], options?: Fuse.FuseOptions) search<T>(pattern: string): T[]; search(pattern: string): any[]; } declare namespace Fuse { export interface FuseOptions { id?: string; caseSensitive?: boolean; include?: string[]; shouldSort?: boolean; searchFn?: any; sortFn?: (a: { score: number }, b: { score: number }) => number; getFn?: (obj: any, path: string) => any; keys?: string[] | { name: string; weight: number }[]; verbose?: boolean; tokenize?: boolean; tokenSeparator?: RegExp; matchAllTokens?: boolean; location?: number; distance?: number; threshold?: number; maxPatternLength?: number; minMatchCharLength?: number; findAllMatches?: boolean; } } 

Declares a class that is globally accessible, for those who do not use modules, or through import for those who are. You can use the UMD style declaration above to get the typing experience that the author intended. The one associated with the library does not contain type information and actually leads to errors in use.

Consider submitting a transfer request for the maintainer with the fix.

Using

You can use this ad in the following ways:

CommonJS, AMD or UMD style

 import Fuse = require('fuse.js'); const myFuseOptions: Fuse.FuseOptions = { caseSensitive: false }; const myFuse = new Fuse([], myFuseOptions); 

ES combined style CommonJS

(when using "module": "system" or "allowSyntheticDefaltImports" ) with SystemJS, the latest web packages, or when passing through Babel. Starting with typescript 2.7, you can also use the new --esModuleInterop flag without any additional module tools or transpilers.

 import Fuse from 'fuse.js'; const myFuseOptions: Fuse.FuseOptions = { caseSensitive: false }; const myFuse = new Fuse([], myFuseOptions); 

As with typescript 2.7, the inter-segment interface es is now available directly in the language. This means that you do not need to use Babel or the JS system or webpack to write the correct import.

+7
source

The trick is to provide access to the Fuse global variable. This is done using webpack with ProvidePlugin

add the following plugin to the webpack plugin array:

  ... new webpack.ProvidePlugin({ "Fuse": "fuse.js" }) ... 
0
source

Source: https://habr.com/ru/post/1013035/


All Articles