nDiviD
@nDiviD
Делать проекты, которыми можно гордиться

Как реализовать динамический import для code splitting в Webpack 2?

Казалось бы все просто. Используем конструкцию вида:
import(/* webpackChunkName: "my-component-chunk" */ 'MyComponent').then((Component) => {
  this.setState({ Component });
})

и радуемся жизни. Ага, компонент работает, но chunk в итоге не создастся - все так же будет в основном.
require.ensure - та же песня
В конфиге webpack (версия 2):
new webpack.optimize.CommonsChunkPlugin({
  children: true,
  async: true,
}),
...
//остальные статичные чанки типа 'vendor'

Что не так?
  • Вопрос задан
  • 1957 просмотров
Решения вопроса 1
nDiviD
@nDiviD Автор вопроса
Делать проекты, которыми можно гордиться
Нашел я решение, опубликовал ответ на подобный вопрос, напишу и сюда. Все довольно просто, если знать нюансы:
1) Нужно понимать, что то что мы хотим загрузить должно быть в отдельном файле - чанке.
2) Для того что бы создался чанк необходимо все импорты этого компонента грузить "лениво". Это очень важно, в свое время именно это мешало мне разбить существующий проект на чанки.
3) Ну и самое простое: грузим через промис import:
const loadEditor = () => import(/* webpackChunkName: "my-best-editor-chunk" */ 'react-dart-editor');
  loadEditor().then(m => use it);

4) Конфиг webpack:
new webpack.optimize.CommonsChunkPlugin({
  children: true,
  async: true,
  minChunks: 2,
}),
new webpack.optimize.CommonsChunkPlugin('manifest'),


Так же можно импортировать и функции.

Я использую такой компонент:
Chunk.jsx
import React, { Component } from 'react';
import PropTypes from 'prop-types';

class Chunk extends Component {
  state = { LoadedComponent: null };

  componentWillMount() {
    if (this.props.preload) this.load(this.props);
  }

  componentWillReceiveProps(nextProps) {
    const { load, component, show } = nextProps;
    if (
      this.props.load !== load ||
      this.props.component !== component ||
      (this.props.show !== show && show)
    ) {
      this.load(nextProps);
    }
  }

  load(props) {
    this.setState({ LoadedComponent: null });
    props.load().then((mod) => {
      this.setState({
        LoadedComponent: props.component ? mod[props.component] : mod.default,
      });
    });
  }

  renderLoading = () => this.props.showLoading ? (<div>Loading</div>) : null;

  render() {
    const { LoadedComponent } = this.state;
    const  { show, ...props } = this.props;
    delete props.load;
    delete props.component;
    if (!show) return null;
    return LoadedComponent ? <LoadedComponent {...props} /> : this.renderLoading();
  }
}

Chunk.defaultProps = {
  showLoading: false,
  preload    : true,
  show       : true,
};

Chunk.propTypes = {
  load       : PropTypes.func.isRequired,
  show       : PropTypes.bool,
  preload    : PropTypes.bool,
  component  : PropTypes.string,
  showLoading: PropTypes.bool,
};

export default Chunk;



Использовать так:
<Chunk
  load={loadEditor} // была уже выше
  component="EditorAside" // если нужно что-то, что импортируется не по дефоулту
  show={true/false} // отображать ли компотнент
  preload={true/false} // осуществлять ли предзагрузку чанка
  props1="1"
  props2="2"
/>
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
UPD2: Решение проблемы
У вас есть название entryPoint и именно его нужно указать как name при конфигурации commonChunksPlugin
entry: {
    application:  /* ... */
  },
....
plugins: {
  new webpack.optimize.CommonsChunkPlugin({
      name: 'application', // <--- Так же как и entryPoint
      async: "vendors", // <--- будет использовано как имя файла (можно оставить просто true). "vendors.js"
      children: true,
      minChunks: 2 // <--- должно быть >= 2
    })
}


Похоже, что это issue. Обсуждение идет тут -https://github.com/webpack/webpack/issues/5109#iss...

OLD:
старый ответ
По-идее у вас должно быть что-то такое:

{
  entry: {
    main: './reactStartup.js'
  },
  output: {
    filename: '[name]-bundle.js',
    chunkFilename: '[name]-chunk.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: 'dist/'
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      async: true,
      children: true,
      minChunks: 2,
    }),
  ]
}


Обратите внимание на minChunks по-умолчанию там скорей всего Inf (документация), а это значит, что в этот чанк ничего не попадает.

Но CommonsChunkPlugin просто выделяет общие модули (которые используются >= 2х раз), а для динамических импортов вам нужен отдельно плагин для babelrc:
// .babelrc
{
  "plugins": [
    "syntax-dynamic-import"
  ]
}


UPD1
Еще дело может быть в модулях - я с вебпаком2 давно отключил преобразование модулей в babel ( "modules": false):
"presets": [
    [
      "env",
      {
        "targets": {
          "node": "current",
          "browsers": "last 2 versions"
        },
        "modules": false,
        "loose": true
      }
    ],
    "react",
  ],
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
21 нояб. 2024, в 19:31
500 руб./за проект
21 нояб. 2024, в 19:28
200000 руб./за проект