Почему Webpack не может найти модуль, а компилятор TypeScript - нет?

Я пытаюсь использовать Fuse в моих приложениях TypeScript. Я импортирую модуль с помощью import * as fuselib from 'fuse.js';, Это хорошо компилируется с tsc, Проблема, с которой я сталкиваюсь, состоит в том, когда я строю проект, используя webpack --config config/webpack.prod.js --progress --profile --bail,

Я получаю ошибку Cannot find module 'fuse.js', Типы предохранителей можно найти здесь. Глядя на мой скомпилированный JS, я не могу найти слово fuse.jsЯ предполагаю, что Webpack искажает имя. Я пытался игнорировать ключевое слово fuse.js в UglifyJsPlugin, но это не помогло.

Моя конфигурация Webpack довольно стандартная.

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'
        })
    ]
};

Чего мне не хватает, чтобы Webpack увидел модуль fuse.js?

2 ответа

Решение

Обновить

Я написал новые декларации для вопроса библиотекаря, основанные на этом ответе. Все должно хорошо работать с последней версией, так как они поставляются с библиотекой.

Ответ

Хорошо, вот что происходит и почему.

Во-первых, Fuze/index.d.ts пытается объявить себя как глобальным, так и внешним окружающим модулем, но делает это оба неправильно. Это делает неправильное использование, такое как то, что привело к вашей ошибке почти неизбежно.

Он содержит объявление модуля, которое содержит объявление класса, предположительно с целью описания формы модуля, но класс не экспортируется.

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

Это означает, что я не могу правильно импортировать модуль, и фактически при попытке импортировать из него значение и / или тип возникает ошибка типа.

Дальше вниз в Fuse/index.d.ts он объявляет о своей глобальной

declare const Fuse;

Предположительно, основываясь на соглашениях и чтении комментариев в реальном Ja vaScript, это должно иметь ту же форму, что и то, что экспортируется из модуля. К сожалению, это имеет тип any тип которого не совпадает с типом запрашиваемого модуля, поскольку он недопустим, и тип класса Fuse который находится внутри указанного модуля, но не экспортируется...

Так почему ошибка? Возможно, у вас в программе есть одно из следующих: import 'fuse'; импортировать предохранитель из 'предохранителя'; импорт * как Предохранитель от 'Предохранитель';

с последующим некоторым использованием Fuse лайк

const myFuse = new Fuse();

Это вызовет импорт для представления времени исполнения Fuse fuse должен передаваться TypeScript, так что вы можете использовать значение, импортированное из модуля.

Чтобы решить проблему, вы можете использовать глобальный const Fuse и не импортировать его никуда. К сожалению, это не то, что предназначено. Автор почти наверняка хотел иметь следующий контент в 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;
    }
}

Который объявляет класс, который доступен глобально, для тех, кто не использует модули, или через импорт для тех, кто есть. Вы можете использовать вышеупомянутое объявление стиля UMD, чтобы получить опыт набора текста, который задумал автор. Тот, который связан с библиотекой, не предоставляет никакой информации о типе и фактически приводит к ошибкам при использовании.

Подумайте об отправке запроса на получение исправления вместе с исправителем.

Использование:

Вы можете использовать эту декларацию следующими способами:

Стиль CommonJS, AMD или UMD

import Fuse = require('fuse.js');

const myFuseOptions: Fuse.FuseOptions = {
  caseSensitive: false
};
const myFuse = new Fuse([], myFuseOptions);

ES со стилем взаимодействия CommonJS

(когда используешь "module": "system" или же "allowSyntheticDefaltImports") с SystemJS, последними Web-пакетами или, если пускают по трубам через Babel. Начиная с машинописного текста 2.7 вы можете использовать также использовать новый --esModuleInterop флаг без каких-либо дополнительных инструментов модуля или транспортеров.

import Fuse from 'fuse.js';

const myFuseOptions: Fuse.FuseOptions = {
    caseSensitive: false
};
const myFuse = new Fuse([], myFuseOptions);

Начиная с машинописного текста 2.7, взаимодействие с модулем es теперь доступно непосредственно на языке. Это означает, что вам не нужно использовать Babel или системный JS или веб-пакет, чтобы написать правильный импорт.

Хитрость заключается в том, чтобы предоставить доступ к глобальной переменной Fuse, Это делается через веб-пакет с ProvidePlugin

добавьте следующий плагин в массив плагинов webpack:

    ...
    new webpack.ProvidePlugin({
        "Fuse": "fuse.js"
    })
    ...
Другие вопросы по тегам