Using webpack/react in plugins

Hello,

recently, a pr [1] was merged that now allow to use webpack [2] power in
plugins as well - it means that now you can:

  • use ES6 in your javascript code, scss/css import etc etc
  • use react, or any other js library that is used by foreman core it self
    in your plugin (including react components that exists in foreman core).
  • start extending your plugin to use advance state handling by leveraging
    redux [3].

whats not complete yet, but we plan on adding (patches are welcomed :))

  • support for per plugin package.json - allowing plugins add more npm
    packages as they require.
  • support for eslint globally, we would prefer to have only one globally
    defined eslintrc file and reuse it across all plugins.
    the idea here is to move away from the current model we have with rubocop
    where each repo needs to "catch up" with foreman, this
    should allow more consistent js code base across plugins.
  • support for jest testing in a similar fashion to rake test.
  • a script that update all dependencies - e.g. bundle update && npm update
    && plugin.each do npm update…
  • extend the react mounter to allow plugins to expose components.
  • add storybook [4] support for plugins just like we have in core [5].

How to use it:

  1. make sure you have a recent foreman develop checkout (including npm
    update etc)
  2. in your view, or layout, deface etc add something like:

<%= javascript_include_tag webpack_asset_paths('your-plugin-bundle',
:extension => 'js'), "data-turbolinks-track" => true %>

  • if you are uncertain on how your bundle name is called, see below for
    more details.
  1. in your plugin, create a directory called 'webpack' (similar to foreman
    core).
  2. inside create a file called index.js and include something like:

import React from 'react';
import ReactDOM from 'react-dom';
import Icon from 'foremanReact/common/Icon';

const reactNode = document.querySelector('#some div that exists already');

if (reactNode) {
ReactDOM.render(
<Icon type='ok' />,
reactNode);
};

  1. execution foreman start on your foreman repo.

couple of more advance things to notice:

  • import React from 'react';
    This actually pulls your dependency (in this case react) to your bundle,
    however, webpack is smart enough to detect common code, and all common code
    will now go to a shared bundle called vendor - e.g.

      Asset     Size  Chunks                    Chunk Names
    

    bundle.js 14.2 MB 0 [emitted] [big] bundle
    taskscore.js 1.8 kB 1 [emitted] taskscore
    vendor.js 2.81 MB 2 [emitted] [big] vendor
    bundle.css 73.7 kB 0 [emitted] bundle
    manifest.json 0 bytes [emitted]

  • this also shows your bundle name, in my case its taskscore - if you are
    still uncertain about the bundle name, you can always simply
    execute ./script/plugin_webpack_directories.rb and see the output there.

[1] https://github.com/theforeman/foreman/pull/4625
[2] https://webpack.github.io
[3] http://redux.js.org/
[4] https://storybook.js.org/
[5] https://cdn.rawgit.com/ohadlevy/foreman/vmware-scsi/index.html