Webpack无法导入图片(使用Express和Angular2的TypeScript)

22

我无法在我的headercomponent.ts文件中导入图片。我怀疑是因为我在编译ts文件(使用webpack ts loader)时做错了什么,因为在使用React时相同的方法可以正常工作(其中组件是用es6编写的)。

错误位置在:

//headercomponent.ts
import {Component, View} from "angular2/core";
import {ROUTER_DIRECTIVES, Router} from "angular2/router";
import {AuthService} from "../../services/auth/auth.service";
import logoSource from "../../images/logo.png"; //**THIS CAUSES ERROR**  Cannot find module '../../images/logo.png'

@Component({
    selector: 'my-header',
    //templateUrl:'components/header/header.tmpl.html' ,
    template: `<header class="main-header">
  <div class="top-bar">
    <div class="top-bar-title">
      <a href="/"><img src="{{logoSource}}"></a>
    </div>

我的Webpack配置是:

// webpack.config.js
'use strict';

var path = require('path');
var autoprefixer = require('autoprefixer');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var basePath = path.join(__dirname,'public');
//const TARGET = process.env.npm_lifecycle_event;
console.log("bp " + basePath)
module.exports = {
  entry: path.join(basePath,'/components/boot/boot.ts'),
  output: {
    path: path.join(basePath,"..","/build"), // This is where images AND js will go
    publicPath: path.join(basePath,"..","/build/assets"),
   // publicPath: path.join(basePath ,'/images'), // This is used to generate URLs to e.g. images
    filename: 'bundle.js'
  },
  plugins: [
    new ExtractTextPlugin("bundle.css")
  ],
  module: {
    preLoaders: [ { test: /\.tsx$/, loader: "tslint" } ],
    //
    loaders: [
      { test: /\.(png!jpg)$/, loader: 'file-loader?name=/img/[name].[ext]'  }, // inline base64 for <=8k images, direct URLs for the rest
      {
        test: /\.json/,
        loader: 'json-loader',
      },
      {
        test: /\.ts$/,
        loader: 'ts-loader',
        exclude: [/node_modules/]
      },
      {
        test: /\.js$/,
        loader: 'babel-loader'
      },
      {
        test: /\.scss$/,
        exclude: [/node_modules/],
        loader: ExtractTextPlugin.extract("style", "css!postcss!sass?outputStyle=expanded")
      },
      // fonts and svg
      { test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: "url-loader?limit=10000&mimetype=application/font-woff" },
      { test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: "url-loader?limit=10000&mimetype=application/font-woff" },
      { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url-loader?limit=10000&mimetype=application/octet-stream" },
      { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file" },
      { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url-loader?limit=10000&mimetype=image/svg+xml" }
    ]
  },
  resolve: {
    // now require('file') instead of require('file.coffee')
    extensions: ['', '.ts', '.webpack.js', '.web.js', '.js', '.json', 'es6', 'png']
  },
  devtool: 'source-map'
};

我的目录结构看起来像这样

-/
 -server/
 -build/
 -node-modules/
 -public/
  -components/
   -boot/
    -boot.component.ts
   -header/
    -header.component.ts
  -images/
   -logo.png
  -services/
-typings/
 -browser/
 -main/
 -browser.d.ts
 -main.d.ts
-tsconfig.json
-typings.json

我的tsconfig文件如下:

 //tsconfig.json
     {
      "compilerOptions": {
        "target": "es5",
        "sourceMap": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "removeComments": false,
        "noImplicitAny": false
      },
      "exclude": [
        "node_modules"
      ]
    }

我怀疑在 TypeScript 编译过程中漏了什么,但不确定是什么。


现在你可以在TypeScript中导入任何你想要的东西,但这并不是完全明显的。请参考这个问题来使用`# declarations.d.ts declare module '*';

index.ts

import * as $ from 'jquery'; import * as _ from 'lodash';` https://github.com/Microsoft/TypeScript/issues/2709
- William S
7个回答

44

问题在于您混淆了TypeScript级别的模块和Webpack级别的模块。

在Webpack中,您导入的任何文件都会经过某些构建管道。

在TypeScript中,只有.ts.js文件是相关的,如果您尝试从file.png导入x,TypeScript就不知道该怎么处理它,Webpack配置不会被TypeScript使用。

在您的情况下,您需要区分关注点,对于TypeScript / EcmaScript代码,请使用import from,对于Webpack特定内容,请使用require

您需要通过在.d.ts文件中定义如下的方式来让TypeScript忽略此特殊的Webpack require语法:

declare function require(string): string;

这将使 TypeScript 忽略 require 语句,从而使 Webpack 能够在构建流水线中处理它。


谢谢,这确实解决了当前的问题。但仍有许多战斗需要打赢。我希望当Angular2稳定下来时会变得更好。我希望有一个官方的入门套件/工作流指南。感觉他们自己对很多事情还不确定。 - Sahil Sharma
这不再完全正确,现在你可以使用 declare module "*"; 相对容易地导入任何你想要的东西。https://github.com/Microsoft/TypeScript/issues/2709 - William S
嘿,我在使用React实现时遇到了问题。请看这里:https://dev59.com/5FUK5IYBdhLWcg3w6zY9 - Mario Petrovic

22

不是:

import image from 'pathToImage/image.extension';

使用:

const image = require('pathToImage/image.extension');

3
这有效,应该是正确答案。然而,对我来说它就像黑魔法一样。我不明白为什么这么基础的东西会这么不直观。你是怎么知道的? - SpaceMonkey
现在我不知道如何实际使用它。如果我记录它,我会看到一个打开图像的URL,这很棒,但是如果我尝试将其用作“img”标记的源,则似乎将其读取为一个非常长的字符串,看起来更像是图像文件(svg)的内容。这非常令人困惑,但感谢您的帮助。 - SpaceMonkey
迄今为止最好的解决方案,我认为这是可读性和可用性方面的最佳实践和方法。您不必声明模块或破解tsc或webpack。 - Florian Leitgeb

12

我正在使用

import * as myImage from 'path/of/my/image.png';

并使用TypeScript创建了一个定义文件

declare module "*.png" {
    const value: any;
    export = value;
}

只有当你使用像webpack中的file-loader这样正确的处理程序时,此方法才有效。因为该处理程序会为您提供文件的路径。


1
关键在于创建TypeScript定义文件。之后,TypeScript允许导入。 - miracle2k
1
问题在于当你在生产环境中构建时,每个静态图像都应该添加md5后缀。因此,你的 import * as myImage from 'path/of/my/image' 就会出现问题。另一个问题是一些小尺寸的图像应该使用 base64 url,url-loader 可以将小尺寸图像转换为 base64 url。在 react 中,所有东西都运行良好。但是在 angular2 中,我仍在寻找解决问题的方法。 - Lin Du

5

对于Christian Stornowski的回答,可以做一点小改进,将导出方式更改为默认导出,即


```export default```
declare module "*.png" {
  const value: string;
  export default value;
}

所以您可以使用以下方式导入图像:

import myImg from 'img/myImg.png';

3
我也遇到了同样的问题,所以我采用了以下方法:
import * as myImage from 'path/of/my/image';

在我的组件中,我只需将导入的图像分配给数据成员;
export class TempComponent{
    public tempImage = myImage;
}

并将其作为模板中的如下所示:

<img [src]="tempImage" alt="blah blah blah">

问题在于当你在生产环境中构建时,每个静态图像都应该添加md5后缀。因此,你的 import * as myImage from 'path/of/my/image' 就会出现问题。 - Lin Du

2
如果您想使用ES6语法进行导入。
首先请确保在您的tsconfig.json中有以下内容:
target: 'es5',
module: 'es6'

以下内容现在应该可以正常工作:

现在应该可以使用以下方法:

import MyImage from './images/my-image.png';

太好了!这对我来说是个解决方案。我只是想知道当我需要导入'common.js'时,我将何时达到第一个限制... - Darkowic

0

为了能够像这样使用默认导入:

import grumpyCat from '../assets/grumpy_cat.jpg';

定义jpg模块声明:

declare module "*.jpg" {
const value: string;
  export default value;
}

在你的tsconfig中使用"module": "es6"(参见@vedran 上面的评论),或者当你使用"module": "commonjs"时,添加"esModuleInterop": true,
  "compilerOptions": {
    "module": "commonjs",
    "target": "es5",
    "esModuleInterop": true,
...

来源:https://github.com/TypeStrong/ts-loader/issues/344#issuecomment-381398818


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接