Разделение компонентов React на отдельные файлы без явного импорта

Я собираюсь написать приложение React на основе бэкэнда Ruby Sinatra. Файл main.js отображает приложение:

import React from 'react';
import ReactDOM from 'react-dom';
import Galery from './components/Galery'

ReactDOM.render(
  <Galery />,
  document.getElementById('app')
);

Раньше у меня были все мои компоненты в одном файле, но я хочу разделить их на отдельные файлы. Мне удалось выполнить этот запуск только в том случае, если я импортирую дочерние компоненты в файл компонентов каждого родителя, например, в Galery.js:

import React, { Component } from 'react';
import Image from 'Image'

class Galery extends Component {
  ...
    <Image ... />
  ...
}

Можно ли избежать явного импорта необходимых компонентов и вместо этого загружать их в файл main.js? Также было бы неплохо не импортировать модуль Component в каждый файл.

Вот моя конфигурация веб-пакета:

module.exports = {
  entry: './react/main.js',
  output: {
    path: __dirname,
    filename: './public/bundle.js'
  },
  resolve: {
    root: __dirname,
    alias: {

    },
    extensions: ['', '.js', '.jsx']
  },
  module: {
    loaders: [
      {
        loader: 'babel-loader',
        query: {
          presets: ['react', 'es2015']
        },
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/
      }
    ]
  }
};

person Berlin_J    schedule 06.11.2017    source источник
comment
Я не уверен, что это сработает для ваших собственных модулей, но вы можете попробовать с ProvidePlugin: webpack .js.org/plugins/provide-plugin. Однако это выглядит как плохая идея, обычно лучше иметь явный импорт, чтобы избежать явной связи между файлами.   -  person Axnyff    schedule 06.11.2017


Ответы (1)


Короткий ответ:

Настоятельно рекомендуется использовать явный импорт везде, где вам нужно, потому что такие инструменты, как webpack, выполняют интеллектуальную оптимизацию размера пакета, удаляя неиспользуемые функции. Имея это в виду, самый короткий ответ таков: то, как вы используете webpack + babel + React, невозможно избежать определения imports для каждого файла.


Более длинный ответ:

Да, вы можете это сделать, но это не так просто. В отличие от Ruby, поиск константы/переменной не работает так же, как в JavaScript. В Ruby отлично работает следующее:

# a.rb
A = 10

# b.rb
require "./a.rb"
puts a # => 10

Это связано с тем, что когда файл a.rb анализируется и включается в b.rb, в Ruby не создается дополнительного подпространства имен. Все единицы верхнего уровня существуют так, как если бы они были определены внутри b.rb. Подробнее об этом< /а>

Чтобы сравнить это с JS, мне нужно немного прояснить, как работает включение модулей. На данный момент довольно сложная ситуация. Давайте сначала рассмотрим NodeJS. В этой небраузерной среде еще не реализована функциональность import, за исключением самых передовых версий с дополнительными флагами (v 9 на сегодняшний день). Поэтому, когда вы используете что-то вроде webpack и import, внутри происходит то, что они преобразуются в собственную прокладку require webpack. И способ преобразования import и require немного отличается, потому что первый является "статическим" загрузчиком стиля, а второй - динамическим загрузчиком стиля. На самом базовом уровне это означает, что операторы import должны быть вверху файла, а операторы require могут быть где угодно, и разрешение файла происходит, когда интерпретатор встречает эту строку. Это имеет странные эффекты, как вы увидите ниже.

Способ работы NodeJS require заключается в идентификации объекта module.exports из включенного файла. Этот объект указывает, какие функции/объекты доступны снаружи. Следовательно, в отличие от Ruby, уже существует неявное локальное пространство имен (или группировка, если хотите) module.exports вместо глобального $LOADED_FEATURES:

// a.js
const a = 10;
module.exports = { a: a };

// b.js

const a = require('./a.js');
console.log(a); // { a: 10 };

Один из способов обойти это — глобальные переменные. Как и в Ruby, в JavaScript есть неявное глобальное пространство имен, особенно часто встречающееся в браузерах через window и global в NodeJS. Одна идея заключается в следующем:

// main.js

import React from 'react';
import ReactDOM from 'react-dom';

import Image from 'components/image.js';
import Gallery from 'components/gallery.js';

window.React = React;
window.ReactDOM = ReactDOM;
window.Image = Image;
window.Gallery = Gallery;

// gallery.js

export default class Gallery extends React.Component {
  render() {
    return <Image />;
  }
}

Однако это не работает. Чтобы эмулировать реальную функциональность ES6 import, которая представляет собой статически определенный набор файлов и функций, webpack пытается эмулировать их с помощью собственной функции require webpack. И это не делает глобально присоединенные константы доступными к моменту выполнения импорта. Таким образом, чтобы заставить это работать, можно использовать более старую загрузку в стиле require, которая изменяет способ работы собственной функции require webpack. Изменив вышеуказанное на:

// main.js

const React = require('react');
const ReactDOM = require('react-dom');

window.React = React;
window.ReactDOM = ReactDOM;

const Image = require('components/image.js').default;
const Gallery = require('components/gallery.js').default;

window.Image = Image;
window.Gallery = Gallery;

// gallery.js

export default class Gallery extends React.Component {
  render() {
    return <Image />;
  }
}

Как видите, это слишком много работы, чтобы запустить приложение JavaScript. Но основная проблема заключается в том, что веб-пакет не может выполнять интеллектуальную оптимизацию, потому что он не знает, какие функции вы не используете. Так что лучше всего этого не делать.

person Kashyap    schedule 07.11.2017