2016-03-22 21 views
14

Non riesco ad importare immagini nel mio headercomponent.ts. Ho il sospetto che è a causa di qualcosa che sto facendo male durante la compilazione ts (usando webpack ts loader) a causa stessa cosa funziona con reagire (in cui i componenti sono scritti in ES6)webpack non in grado di importare immagini (utilizzando express e angular2 in dattiloscritto)

La posizione di errore è

//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> 

mia webpack config è

// 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' 
}; 

e la mia struttura di directory simile a questo

-/ 
-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 

mio file TSconfig è la seguente:

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

Ho il sospetto che sto scompigliando qualche cosa nella compilation dattiloscritto, non so cosa

+0

è possibile importare quello che vuoi in dattiloscritto ora, ma non è del tutto evidente. Vedi questo problema per usare '# declarations.d.ts dichiarare il modulo '*'; # index.ts importazione * come $ da 'jquery'; import * come _ da 'lodash'; 'https://github.com/Microsoft/TypeScript/issues/2709 –

risposta

23

Il problema è che si confondono moduli di livello tipografico e moduli di livello webpack.

In Webpack qualsiasi file importato passa attraverso alcune pipeline di build.

a macchina solo .ts e .js file sono pertinenti e se si tenta di import x from file.png dattiloscritto non sa cosa fare con esso, Webpack config non viene utilizzato da dattiloscritto.

Nel tuo caso è necessario separare i dubbi, utilizzare import from per il codice TypeScript/EcmaScript e utilizzare require per specifiche di Webpack.

Si avrebbe bisogno di fare dattiloscritto ignorare questo speciale sintassi Webpack require con una definizione come questa in un file .d.ts:

declare function require(string): string; 

Questo renderà dattiloscritto ignorare la richiedono dichiarazioni e Webpack sarà in grado di elaborare in la pipeline di costruzione.

+0

Grazie, questo ha risolto il problema attuale. Ma ancora ci sono ancora tante battaglie da vincere. Spero che questo diventi migliore quando angular2 diventa stabile. Vorrei che ci fosse un kit di partenza ufficiale/linee guida per il flusso di lavoro. Sembra che loro stessi siano ancora insicuri di molte cose. –

+0

Questo non è più il caso, ora puoi importare facilmente ciò che vuoi usando 'declare module '*"; '. https://github.com/Microsoft/TypeScript/issues/2709 –

11

Invece di:

import image from 'pathToImage/image.extension'; 

Usa:

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

ha funzionato, dovrebbe essere la risposta corretta. Tuttavia, è come la magia nera per me. Non capisco come qualcosa di così fondamentale debba essere così poco intuitivo. Come lo sapevi? –

+0

ora non so come usarlo realmente .. Se lo registro, vedo un URL che apre l'immagine che è grande, ma se provo a usarlo come sorgente per un tag "img", sembra per leggerlo come una stringa molto lunga che assomiglia più al contenuto del file immagine (svg). Questo è estremamente confuso, ma grazie per il vostro aiuto –

+0

La migliore soluzione di gran lunga e, a mio parere, la migliore pratica e la strada da percorrere per quanto riguarda la leggibilità e l'usabilità. Non devi dichiarare moduli o hack tsc o webpack. –

1

Ho anche avuto lo stesso problema in modo seguente approccio che ho usato:

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

Nel mio componente ho semplicemente assegnato l'immagine importata a un membro di dati;

export class TempComponent{ 
    public tempImage = myImage; 
} 

e utilizzati nel modello come:

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

Il problema è quando si costruisce in produzione, ogni immagine statica dovrebbe aggiungere il suffisso 'md5'. Quindi, il tuo 'import * as myImage from' path/of/my/image'' è rotto. – novaline

5

sto usando

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

e ha creato una definizione dattiloscritto con

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

Questo funziona solo quando avere un gestore corretto come il file -loader in webpack. Perché questo gestore ti darà un percorso per il tuo file.

+0

La chiave per me era creare il file di definizione del dattiloscritto. Dopodiché, Typescript consente l'importazione. – miracle2k

+0

Il problema è quando si costruisce in produzione, ogni immagine statica dovrebbe aggiungere il suffisso 'md5'. Quindi, il tuo 'import * as myImage from' path/of/my/image'' è rotto. Un altro problema è che alcune immagini di piccole dimensioni dovrebbero essere usate dall'URL 'base64',' url-loader' può convertire l'immagine di piccola dimensione nell'URL 'base64'.con 'react', tutto funziona bene. Ma 'angular2', sto ancora cercando un modo per risolvere i miei problemi. – novaline

1

Un piccolo miglioramento alla risposta di Christian Stornowski sarebbe quello di rendere il default di esportazione, vale a dire declare module "*.png" { const value: string; export default value; }

modo da poter importare un'immagine mediante:

import myImg from 'img/myImg.png';