【问题标题】:Splitting React components in seperate files without explicite import在没有显式导入的情况下将 React 组件拆分为单独的文件
【发布时间】:2018-04-18 16:06:31
【问题描述】:

我正在编写一个基于 Ruby Sinatra 后端的 React 应用程序。一个 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 模块。

这是我的 webpack 配置:

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)/
      }
    ]
  }
};

【问题讨论】:

  • 我不确定它是否适用于您自己的模块,但您可以尝试使用 ProvidePlugin:webpack.js.org/plugins/provide-plugin。但是,这看起来是个坏主意,通常最好有显式导入以避免文件之间显式耦合。

标签: reactjs webpack sinatra code-splitting


【解决方案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 中定义一样。 More on this

为了将其与 JS 进行比较,我需要澄清一下模块包含的工作方式。到目前为止,这是一个相当复杂的情况。让我们首先考虑 NodeJS。在这个非浏览器环境中,还没有实现import 功能,除了带有额外标志的前沿版本(截至今天的第 9 版)。因此,当您使用 webpackimport 之类的东西时,内部发生的事情是它们被转换为 webpack 自己的 require shim。而importrequire 的转换方式略有不同,因为前者是“静态”样式加载器,而后者是动态样式加载器。在非常基本的层面上,这意味着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 和 NodeJS 中的 global 更常见。一个想法如下:

// 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 尝试通过 webpack 自己的 require 函数来模拟它们。这不会使全局附加的常量在导入完成时可用。因此,要完成这项工作,一种解决方法是使用旧的 require 样式加载,它改变了 webpack 自己的 require 函数的工作方式。通过将以上内容更改为:

// 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 应用程序运行起来,工作量太大了。但是主要的问题是 webpack 不能做任何智能优化,因为它不知道你没有使用哪些函数。所以最好避免做这一切。

【讨论】:

    猜你喜欢
    • 2016-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多