2015-05-20 2 views
38

У меня есть приложение React с компонентами, написанными на ES6, - с помощью Babel и Webpack.Импорт файлов CSS в изоморфных компонентах React

В некоторых местах я хотел бы включать конкретные CSS файлы с определенными компонентами, как это было предложено в react webpack cookbook

Однако, если в какой-либо компонента файла, который я требуется статический CSS актив, например:

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

Тогда компиляция завершается с ошибкой:

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) 

Это кажется, что если я попытаюсь REQ uire файл CSS в файле Component, тогда загрузчик Babel будет интерпретировать это как другой источник и попытаться перевести CSS в Javascript.

Ожидается ли это? Есть ли способ достичь этого - позволяя переделанным файлам явно ссылаться на статические активы, которые нельзя перекрыть?

Я уточнял погрузчиков и .js/JSX и CSS активов следующим образом:

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

просмотреть full webpack config file

ПОЛНОЕ ОПИСАНИЕ НИЖЕ:

webpack.common.js - База WebPack конфигурации Я использую, поэтому я могу делиться свойствами между dev и production.

Gruntfile.js - Gruntfile используется для разработки. Как вы видите, для этого требуется конфигурация webpack выше и добавляет к ней некоторые свойства разработки. Может ли это вызвать проблему?

Html.jsx - Мой компонент HTML jsx, который пытается импортировать/требовать CSS. Это изоморфное приложение (с использованием Fluxbile), поэтому необходимо иметь фактический HTML как обработанный компонент. Используя инструкцию require, увиденную в этом файле, в любой части моего приложения выдает описанную ошибку.

Кажется, что-то связано с ворчанием. Если я просто компилирую с webpack --config webpack.common.js, то я не получаю ошибок.

Короткий ответ: Это ошибка времени выполнения узла. Попытка загрузить CSS на сервере в изоморфных приложениях не является хорошей идеей.

+2

Ваша конфигурация в порядке. Я попытался запустить его в приложении с включением css, и это сработало. Проверяйте другие вещи - возможно, вы запускаете webpack с совершенно другим конфигурационным файлом :) или что-то не так с пакетами. Опубликуйте больше информации - ваш package.json, как вы запускаете webpack и т. Д. Возможно, мы выясним. – Viacheslav

+0

Спасибо, я предоставил больше информации выше. Кажется, что проблема вызвана где-то ворчанием, поскольку компиляция непосредственно через webpack в порядке. – duncanhall

+0

Может показаться интересным для 'console.log()' your 'webpackConfig' в файле grunt –

ответ

62

Вы не можете запрашивать css в компоненте, который вы рендерите на сервере. Один из способов борьбы с ним - проверить, не является ли это браузером, прежде чем требовать css.

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

Для того, чтобы сделать возможным, вы должны установить process.env.BROWSER к false (или удалить) на сервере server.js

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

и установить его в true для браузера. Вы делаете это с DefinePlugin WebPack в конфиге - webpack.config.js

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

Вы можете увидеть это в действии в Isomorphic500 приложение gpbl в.

+1

Миллион раз да! Спасибо. – duncanhall

+1

Я думаю, что у меня такая же проблема, но кажется уродливым, чтобы обернуть импорт .css с условной логикой, как это. Есть ли другое решение? @snegostup – Muers

+1

Я считаю, что есть способ импорта css и т. д. на стороне сервера, но для этого требуется связать ваш серверный код с Webpack, используя отдельную конфигурацию для той, которая используется для вашей клиентской стороны bundle.js Мне не нравится вариант использования Decorators, и мне также не нравится идея, что вы можете требовать от клиента не JS-модулей для ситуаций, когда у конечного пользователя отключен Javascript. В настоящее время я изучаю специфику на Webpack Server-Side –

1

Возможно, у вас есть ошибка в вашей конфигурации Webpack, где вы используете babel-loader для всех файлов, а не только файлы .js. Вы хотите использовать загрузчик css для файлов .css.

Но вы не должны использовать import для загрузки любого другого модуля, кроме модулей Javascript, поскольку после импорта в браузерах вы сможете импортировать только файлы Javascript. Используйте require вместо этого в тех случаях, когда вам нужна специальная функциональность Webpack.

ОРИГИНАЛЬНЫЙ ПОСТ

Webpack использует require и Бабель позволяет использовать import из ES6, которые в основном делают то же самое (и Бабель transpiles импорта к требуют заявления), но они не являются взаимозаменяемыми. Функция Webpacks require позволяет указать не только имя модуля, но и указать загрузчики, что вы не можете сделать с ES6 import. Поэтому, если вы хотите загрузить файл CSS, вы должны использовать require вместо import.

Причина в том, что Babel является просто транспилером для того, что входит в ES6, и ES6 не позволит вам импортировать файлы CSS. Так что Вавилон не позволит вам это сделать.

+0

Спасибо - к сожалению, похоже, что это не так. Замена оператора import оператором require дает точно такую ​​же ошибку. Это в основном то, что я ожидал бы - если Бабел переводит «импорт» в «требовать», и тогда мы увидим, что ошибка, использующая «требовать», в первую очередь, должна была вызвать ту же ошибку. – duncanhall

+0

Вероятно, у вас есть ошибка в конфигурации вашего Webpack, где вы используете 'babel-loader' для всех файлов, когда он должен использоваться только для файлов .js'. –

+1

babel-loader не разрешает, webpack делает. Так что прекрасно «импортировать» файл css, если webpack использует загрузчик css. – gpbl

1

Убедитесь, что вы используете погрузчики в вашем WebPack конфигурации:

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

Спасибо, проблема не в том, что отсутствует laoder, у меня есть эти на месте. Проблема в том, что Babel видит оператор import/require и пытается импортировать CSS как «трансляционный» ресурс источника. – duncanhall

+1

Без какого-либо кода/конфигурации трудно сказать, но кажется, что webpack передает файл .css в загрузчик babel: он не должен. Если это так, я считаю, что в вашем конфиге что-то не так. – gpbl

+0

Спасибо, я добавил ссылку на полный файл конфигурации в исходном сообщении. Если вы можете увидеть какие-либо проблемы, то это оценено. – duncanhall

0

Я, наконец, понял, что эта ошибка не происходящий на этапе компиляции, а во время выполнения. Поскольку это приложение ismorphic, компоненты и любые связанные с ними зависимости сначала анализируются на сервере (то есть в узле). Именно это вызывает ошибку.

Спасибо за все предложения, я опубликую больше, если/когда я выясню, как иметь таблицы стилей для каждого компонента в изоморфном приложении.

+5

Какое решение вы остановили в конце - декоратор, условная логика или что-то еще? Imo условная логика кажется немного взломанной, и декоратор просто кажется немного выключен. Я чувствую, что там может быть решение, которое просто справляется с этой проблемой, настраивая babel. –

8

Если вы создаете изоморфное приложение с ES6 и хотите включать CSS при рендеринге на сервере (важно, чтобы основные стили могли быть отправлены клиенту в первом ответе HTTP), проверьте декодер @withStyles ES7, используемый в Набор реагентов для начинающих.

Эта маленькая красавица помогает пользователям видеть ваш контент со стилями, когда страница сначала отображается. Вот example isomorphic app Я использую эту технику. Просто найдите код для @withStyles, чтобы узнать, как он используется.Это идет немного что-то вроде этого:

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

@withStyles(styles) 
class ScheduleList extends Component { 
0

Я также встречался с той же проблемой, когда я хочу сделать на стороне сервера визуализации ,

Поэтому я пишу плагин postcss, postcss-hash-classname.

Вы не требуете непосредственно css.

Вам необходим файл css classname js.

Поскольку все, что вам нужно, это файл js, вы можете сделать рендеринг на стороне сервера как обычно.

Кроме того, этот плагин также использует ваше имя класса и путь к файлу для генерации уникального хэша для решения проблемы с областью css.

Вы можете попробовать!

2

Я использовал этот babel plugin с успехом, чтобы решить аналогичную проблему с меньшими, svg и изображениями. Но он должен работать с любыми активами non js.

Он переписывает весь импорт активов в переменные, поэтому, пока вы запускаете скомпилированный код только на сервере и имеете пакет, созданный с помощью webpack для клиента, все должно быть хорошо.

Единственный недостаток заключается в том, что он onlyworks с именованным импортом, так что вам придется:

import styles from './styles.css'; 

для того, чтобы заставить его работать.

3

У нас была аналогичная проблема с нашим изоморфным приложением (и многие другие проблемы, вы можете найти details here). Что касается проблемы с импортом CSS, то сначала мы использовали process.env.BROWSER. Позже мы переключились на babel-plugin-transform-require-ignore. Он отлично работает с babel6.

Все, что вам нужно иметь следующую секцию в .babelrc

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

После этого запустите приложение с BABEL_ENV = «узел». Как что:

BABEL_ENV='node' node app.js. 

Here is пример того, как производство конфигурации может выглядеть следующим образом.

+0

, или вы можете включить его в настройках babel-register, которые вы загружаете для сервера (чтобы не испортить переменную env.): require ("babel-register") ({ плагины: [] [ "transform-require-ignore", {"extensions": [".css"] } ] ] }) – Viacheslav

Смежные вопросы