koltyakov / generator-sppp

🐾 SP Pull-n-Push - Yeoman generator for SharePoint client-side applications
MIT License
64 stars 12 forks source link

React development environment #42

Closed hasankoroglu closed 4 years ago

hasankoroglu commented 4 years ago

Hello,

Is there a way to work with react development environment. am i have to change the script tag as react.development.js

Thanks

koltyakov commented 4 years ago

Hey @hasankoroglu,

This is possible, I usually add a handler for a local serve mode to replace prod with dev versions for debug purposes. Something this way:

// webpack.config.js

// ...

config.devServer.before = (app, ...args) => {

  const webpartsHandler = (req, res, next) => {
    if (req.url.indexOf('.html') === -1) {
      return next();
    }
    const wpPath = join(contentBase, req.url.split('?')[0]);
    const wbHtml = fs.readFileSync(wpPath, { encoding: 'utf-8' });

    const replacers = [
      ['/react.production.min.js', '/react.development.js'],
      ['/react-dom.production.min.js', '/react-dom.development.js'],
    ];

    const wpBody = replacers.reduce((res, rpl) => res.replace(rpl[0], rpl[1]), wbHtml);

    res.send(wpBody);
  };
  app.get(`/webparts/*`, webpartsHandler);

  initialBefore(app, ...args);
};

// ...

This code is taken out of a random project to transfer the idea. It could contain errors as a result of trimming out project-dependent lines.

hasankoroglu commented 4 years ago

Thanks Andrew for the quick answer. I'm not good at with webpack and js as you :) can you send a code sample, how to use this config.

koltyakov commented 4 years ago

Well, the full version of webpack.config.js:

const fs = require('fs');
const { join } = require('path');
const { DefinePlugin } = require('webpack');
const configs = require('sp-build-tasks/dist/webpack/config/v2');

require('dotenv').config();

const defineOptions = Object.assign(
  // Options from ./config/app.json are passed to Define plugin
  {
    APP_CONFIG: JSON.stringify(
      require(join(process.cwd(), process.env.APP_JSON || './config/app.json'))
    ),
    SPPP_ASSETS_LOCATION: JSON.stringify('SPWeb')
  },
  // All environment variables which start with "SPPP_" are passed to Define plugin
  Object.keys(process.env).filter(key => key.indexOf('SPPP_') === 0).reduce((res, key) => {
    res[key] = JSON.stringify(process.env[key]);
    return res;
  }, {})
);

configs.forEach(config => {

  delete config.output.publicPath; // use dynamic __webpack_public_path__

  // Define plugin
  config.plugins = config.plugins || [];
  config.plugins.push(new DefinePlugin(defineOptions));

  // Exclude "heavy" 3rd parties
  config.externals = Object.assign(config.externals || {}, {
    'react': 'React',
    'react-dom': 'ReactDOM',
    '@fluentui/react': 'FluentUIReact'
  });

  // Register custom workbench transformation
  const initialBefore = config.devServer.before;
  const contentBase = config.devServer.contentBase || join(process.cwd(), './dist');
  config.devServer.before = (app, ...args) => {

    const webpartsHandler = (req, res, next) => {
      if (req.url.indexOf('.html') === -1) {
        return next();
      }
      const wpPath = join(contentBase, req.url.split('?')[0]);
      const wbHtml = fs.readFileSync(wpPath, { encoding: 'utf-8' });

      const replacers = [
        ['/react.production.min.js', '/react.development.js'],
        ['/react-dom.production.min.js', '/react-dom.development.js'],
      ];

      const wpBody = replacers.reduce((res, rpl) => res.replace(rpl[0], rpl[1]), wbHtml);

      res.send(wpBody);
    };
    app.get(`/webparts/*`, webpartsHandler);

    initialBefore(app, ...args);
  };

});

module.exports = configs;

While cewp contains react.production.min.js and react-dom.production.min.js:

<!-- {{ publishPath }}/webparts/{{ fileName }} -->

<meta http-equiv="Content-type" content="text/html; charset=utf-8" />

<link type="text/css" rel="stylesheet" href="{{ publishPath }}/styles/app.css?v={{ assetsVersion }}">

<!--[if IE]>-->
<script type="text/javascript" src="{{ publishPath }}/scripts/polyfills.js"></script>
<!--<![endif]-->
<script type="text/javascript" src="{{ publishPath }}/libs/react.production.min.js"></script>
<script type="text/javascript" src="{{ publishPath }}/libs/react-dom.production.min.js"></script>
<script type="text/javascript" src="{{ publishPath }}/libs/fluentui-react.min.js"></script>

<h2>SPFlow Grid Sample</h2>
<div id='spflow-grid-container'></div>

<script type="text/javascript" src="{{ publishPath }}/scripts/app.js?v={{ assetsVersion }}"></script>

During the serve with npm run start these are replaced with development versions.

I will think out, maybe I can do it a bit simpler in HBS compiler task. But currently, that's the way I did it. Also, you can have a separate .cewp.hbs for debug and for prod as well.

hasankoroglu commented 4 years ago

You are best of the best Andrew, very very thanks.

koltyakov commented 4 years ago

Thanks!