2015-05-20 4 views
38

Ho un'applicazione React con componenti scritti in ES6 - traspiled tramite Babel e Webpack.Importazione di file CSS in componenti isomorfi di reazione

In alcuni punti che vorrei includere i file CSS specifici con componenti specifici, come suggerito in react webpack cookbook

Tuttavia, in caso di file di Componente Ho bisogno di una risorsa CSS statica, ad esempio:

import '../assets/css/style.css';

Poi la compilazione fallisce con un errore:

SyntaxError: <PROJECT>/assets/css/style.css: Unexpected character '#' (3:0) 
    at Parser.pp.raise (<PROJECT>\node_modules\babel-core\lib\acorn\src\location.js:73:13) 
    at Parser.pp.getTokenFromCode (<PROJECT>\node_modules\babel-core\lib\acorn\src\tokenize.js:423:8) 
    at Parser.pp.readToken (<PROJECT>\node_modules\babel-core\lib\acorn\src\tokenize.js:106:15) 
    at Parser.<anonymous> (<PROJECT>\node_modules\babel-core\node_modules\acorn-jsx\inject.js:650:22) 
    at Parser.readToken (<PROJECT>\node_modules\babel-core\lib\acorn\plugins\flow.js:694:22) 
    at Parser.pp.nextToken (<PROJECT>\node_modules\babel-core\lib\acorn\src\tokenize.js:98:71) 
    at Object.parse (<PROJECT>\node_modules\babel-core\lib\acorn\src\index.js:105:5) 
    at exports.default (<PROJECT>\node_modules\babel-core\lib\babel\helpers\parse.js:47:19) 
    at File.parse (<PROJECT>\node_modules\babel-core\lib\babel\transformation\file\index.js:529:46) 
    at File.addCode (<PROJECT>\node_modules\babel-core\lib\babel\transformation\file\index.js:611:24) 

sembra che se provo e req uire un file CSS in un file Component, quindi il loader Babel interpreterà come un'altra fonte e tenterà di trasporre il CSS in Javascript.

È previsto? C'è un modo per raggiungere questo obiettivo - consentendo ai file transpiled di fare riferimento esplicito a risorse statiche che non devono essere transpiled?

Ho specificato caricatori per le attività sia js/JSX e CSS come segue:

module: { 
    loaders: [ 
     { test: /\.css$/, loader: "style-loader!css-loader" }, 
     { test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'babel'} 
    ] 
    } 

Guarda le full webpack config file

DETTAGLI integralmente:

webpack.common.js - Una configurazione di base webpack Io uso, quindi posso condividere le proprietà tra dev e produzione.

Gruntfile.js - Gruntfile utilizzato per lo sviluppo. Come puoi vedere richiede la configurazione del pacchetto web sopra e aggiunge alcune proprietà di sviluppo. Questo potrebbe causare il problema?

Html.jsx - Il mio componente jsx HTML che tenta di importare/richiedere il CSS. Questa è un'app isomorfa (usando Fluxbile), quindi necessita dell'HTML come componente renderizzato. Utilizzando l'istruzione require vista in questo file, in qualsiasi parte della mia applicazione, viene fornito l'errore descritto.

sembra essere qualcosa a che fare con grugnito. Se mi limito a compilare con webpack --config webpack.common.js allora non ho errori.

Risposta breve: È un errore di runtime del nodo. Cercare di caricare CSS sul server in app isomorfe non è una buona idea.

+2

La tua configurazione è ok. Ho provato a eseguirlo su un'app con inclusione CSS e ha funzionato. Controlla altre cose - forse esegui il webpack con file di configurazione completamente diversi :) o è qualcosa di sbagliato nei pacchetti. Pubblica più informazioni - il tuo package.json, come esegui il webpack, ecc. Forse lo scopriremo. – Viacheslav

+0

Grazie, ho fornito maggiori informazioni sopra. Il problema sembra essere causato da qualche parte in grunt, in quanto la compilazione direttamente tramite webpack va bene. – duncanhall

+0

Potrebbe essere interessante per 'console.log()' il tuo 'webpackConfig' nel gruntfile –

risposta

62

Non è possibile richiedere css nel componente che si sta eseguendo il rendering sul server. Un modo per affrontarlo è controllare se è un browser prima di richiedere il css.

if (process.env.BROWSER) { 
    require("./style.css"); 
} 

Al fine di rendere possibile si dovrebbe impostare process.env.BROWSER-false (o eliminarlo) sul server server.js

delete process.env.BROWSER; 
... 
// other server stuff 

e impostarlo true per il browser. Lo si fa con DefinePlugin di webpack nella configurazione - webpack.config.js

plugins: [ 
    ... 
    new webpack.DefinePlugin({ 
     "process.env": { 
      BROWSER: JSON.stringify(true) 
     } 
    }) 
] 

È possibile vedere in azione in Isomorphic500 app di gpbl.

+1

Un milione di volte sì! Grazie. – duncanhall

+1

Penso di avere lo stesso problema, ma mi sembra davvero brutto dover avvolgere le importazioni .css con una logica condizionale come questa. C'è un'altra soluzione? @snegostup – Muers

+1

Credo che ci sia un modo per importare css ecc lato server, ma richiede il bundle del codice lato server con Webpack usando una configurazione separata a quella utilizzata per il bundle.js lato client Non mi piace il possibilità di utilizzare Decorators e inoltre non mi piace l'idea di poter richiedere solo moduli JS non client per situazioni in cui l'utente finale ha Javascript disabilitato. Attualmente sto ricercando specifiche su Webpack Server-Side –

1

Probabilmente si è verificato un errore nella configurazione del Webpack in cui si utilizza lo babel-loader per tutti i file e non solo i file .js. Si desidera utilizzare un caricatore di css per i file .css.

Ma non è necessario utilizzare import per caricare qualsiasi altro modulo rispetto ai moduli Javascript, perché una volta che le importazioni sono state implementate nei browser, sarà possibile solo importare file Javascript. Utilizzare require invece nei casi in cui è necessaria la funzionalità specifica di Webpack.

ORIGINALE POST

Webpack utilizza require e Babel consente di utilizzare import da ES6, che per lo più fare la stessa cosa (e Babel transpiles l'importazione una dichiarazione richiedere), ma non sono intercambiabili. La funzione Webpacks require consente di specificare più di un semplice nome di modulo, consente di specificare anche i programmi di caricamento, cosa che non è possibile fare con ES6 import s. Quindi, se vuoi caricare un file CSS, devi usare require invece di import.

La ragione è che Babel è solo un traspolatore per ciò che sta arrivando in ES6 e ES6 non consente di importare file CSS. Quindi Babel non ti permetterà nemmeno di farlo.

+0

Grazie - sfortunatamente questo non sembra essere il caso. Sostituire la dichiarazione di importazione con un'istruzione require fornisce esattamente lo stesso errore. Questo è principalmente ciò che mi aspetterei - se Babel traspone un 'import' a un' require' e poi vediamo l'errore, utilizzando il 'require' in primo luogo ci si aspetta che produca lo stesso errore. – duncanhall

+0

Probabilmente hai un errore nella configurazione del Webpack in cui usi il 'babel-loader' per tutti i file, quando dovrebbe essere usato solo per i file' .js'. –

+1

babel-loader non risolve richiede, webpack fa. Quindi va bene "importare" un file css, a patto che webpack usi un css loader. – gpbl

1

Assicurarsi che si sta utilizzando i caricatori nella configurazione webpack:

module: { 
    loaders: [ 
     { test: /\.jsx$/, exclude: /node_modules/, loader: "babel" }, 
     { test: /\.css$/, loader: "style!css" } 
    ] 
    } 
+0

Grazie, il problema non è con un laoder mancante, ho questi in atto. Il problema è che Babel sta osservando la dichiarazione import/require e sta tentando di importare il CSS come risorsa sorgente 'transpilable'. – duncanhall

+1

È difficile dire un po 'di codice/configurazione, ma sembra che il webpack stia passando il file .css al babel-loader: non dovrebbe. Se lo fa, credo che ci sia qualcosa di sbagliato nella tua configurazione. – gpbl

+0

Grazie, ho aggiunto un collegamento al file di configurazione completo nel post originale. Se riesci a vedere qualche problema, è apprezzato. – duncanhall

0

ho finalmente capito che questo errore non è originario in fase di compilazione, ma piuttosto in fase di esecuzione. Poiché si tratta di un'app ismorphic, i componenti e tutte le dipendenze che hanno saranno prima analizzati sul server (cioè nel nodo). È questo che sta causando l'errore.

Grazie per tutti i suggerimenti, posterò di più se/quando capirò come avere fogli di stile per componente in un'applicazione isomorfa.

+5

Alla fine, quale soluzione hai deciso: decoratore, logica condizionale o qualcos'altro? Imo la logica condizionale sembra un po 'hacky e il decoratore sembra appena un po' fuori ... Mi sento come se ci potesse essere una soluzione là fuori che si occupa solo di questo problema attraverso la configurazione di babele. –

8

Se si sta costruendo un'app isomorfa con ES6 e si desidera includere CSS durante il rendering sul server (importante affinché gli stili di base possano essere inviati al client nella prima risposta HTTP), consultare il decoratore ES2 @withStyles utilizzato in React Starter Kit.

Questa piccola bellezza consente agli utenti di vedere i tuoi contenuti con gli stili quando la pagina viene prima sottoposta a rendering. Ecco un example isomorphic app Sto costruendo sfruttando questa tecnica. Basta cercare il codice base per @withStyles per vedere come viene utilizzato.Va un po 'di qualcosa di simile:

import React, { Component, PropTypes } from 'react'; 
import styles from './ScheduleList.css'; 
import withStyles from '../../decorators/withStyles'; 

@withStyles(styles) 
class ScheduleList extends Component { 
0

Ho anche incontrato lo stesso problema quando voglio fare il rendering lato server .

Così scrivo un plugin postcss, postcss-hash-classname.

Non è necessario il css direttamente.

È necessario il file js classname css.

Perché tutto ciò che serve è il file js, è possibile eseguire il rendering lato server come al solito.

Inoltre, questo plugin utilizza anche il nome della classe e il percorso del file per generare hash univoci per risolvere il problema dell'ambito css.

Puoi provarlo!

2

Ho usato questo babel plugin con successo per risolvere un problema simile con meno, svg e immagini. Ma dovrebbe funzionare con qualsiasi risorsa non js.

Riscrive tutte le importazioni di beni in variabili, quindi se si esegue il codice compilato solo sul server e si dispone di un pacchetto creato con il Webpack per il client, dovrebbe essere corretto.

L'unico svantaggio è che onlyworks con le importazioni di nome, quindi dovrete per:

import styles from './styles.css'; 

al fine di farlo funzionare.

3

Abbiamo avuto un problema simile con la nostra app isomorfa (e molti altri problemi, è possibile trovare details here). Per quanto riguarda il problema con l'importazione CSS, inizialmente stavamo usando process.env.BROWSER. Più tardi siamo passati a babel-plugin-transform-require-ignore. Funziona perfettamente con babel6.

Tutto ciò che serve è quello di avere la seguente sezione nel tuo .babelrc

"env": { 
    "node": { 
    "plugins": [ 
     [ 
     "babel-plugin-transform-require-ignore", { "extensions": [".less", ".css"] } 
     ] 
    ] 
    } 
} 

Dopo di che eseguire l'applicazione con BABEL_ENV = 'nodo'. Come quella:

BABEL_ENV='node' node app.js. 

Here is un esempio di come una configurazione di produzione può sembrare.

+0

oppure puoi abilitarla nelle opzioni 'babel-register che carichi per il server (di non pasticciare con la variabile env.): richiedono ("Babel-register") ({ plugin: [ [ "trasformare-require-ignorare", { "estensioni": [ "css"] } ] ] }) – Viacheslav