nytimes/kyt

user survey: what are you doing in your modifyWebpackConfig?

jaredmcdonald opened this issue · 11 comments

As an attempt to build even better defaults into kyt, we're wondering what you're currently doing in your modifyWebpackConfig in kyt.config.js. Please comment or leave thumbs on existing uses--we'll likely use the feedback here to set future priorities for kyt 😁 ✨

In a nutshell:

  • Making sure we can use Inline SVG by editing the url loader behaviour.
  • Set a few constants we can use in components to change behaviour based on environment (CLIENT/SERVER/PRODUCTION/DEVELOPMENT)

https://github.com/cleverfranke/cf-kyt-starter-universal-redux/blob/master/kyt.config.js

Slightly relevant, we've changed the serverURL for production environments (npm run start) so it runs on another port. This is to prevent caching issues. We're using ServiceWorkers in production builds and it's quite annoying if ServiceWorkers hijack your development environment.

https://github.com/cleverfranke/cf-kyt-starter-universal-redux/blob/master/kyt.config.production.js

  • react-svg-loader turns svg files into react components with svgo. No need for an icon set! In order to get kyt working, we had to manually exclude /\.svg$/ from kyt's file loader. Took a bit of tinkering but well worth it.
  • We also modify our jest config to exclude react-storybook stories from coverage reports and to output Jest coverage results in JUnit XML via jest-junit for Jenkins integration.
  • Instead of messing around with webpack.DefinePlugin() for flags, we use babel-plugin-transform-define and make a special config.js file with globals like API_URL, STAGE, S3_URL, etc.. Our node Ansible playbook has a task that replaces this file before builds with the correct variables depending on the environment. This actually had some fantastic side effects: we no longer have a special reducer for config/environment and we no longer needed certain environment-related selectors in our thunk actions.
// kyt.config.js
module.exports = {
  reactHotLoader: true,
  debug: false,
  modifyWebpackConfig: (baseConfig, options) => {
    baseConfig.module.rules.unshift({
      test: /\.svg$/,
      loaders: [
        'babel-loader',
        {
          loader: 'react-svg',
          query: {
            es5: false,
            jsx: true,
            svgo: {
              plugins: [{ removeTitle: false }],
              floatPrecision: 2
            }
          }
        }
      ]
    });

    baseConfig.module.rules[2].exclude = /\.svg$/;

    return baseConfig;
  },
  modifyJestConfig: config => {
    config.collectCoverageFrom = [
      '**/*.{js,jsx}',
      '!**/.storybook/**',
      '!**/flowtyped/**',
      '!**/*.story.js',
      '!**/node_modules/**'
    ];

    config.testResultsProcessor = '../node_modules/jest-junit';
    
    return config;
  }
};

And our .babelrc

{
  "presets": [
    "react-app"
  ],
  "plugins": [
    "dynamic-import-webpack",
    [
      "transform-define",
      "./config.js"
    ]
  ]
}
// config.js (local environment)
// We check the local version into git.
// This gets replaced by an Ansible task before builds.
module.exports = {
  APP_VERSION: '0.0.1',
  API_VERSION: 'v2.2',
  API_URL: 'http://localhost:8080',
  STAGE: 'local', 
  HTTPS: false,
  S3_URL: 'https://XXXXXX.s3-website-us-east-1.amazonaws.com/',
  WP_URL: 'https://XXXXXXXX.com',
  GA: 'XXXXXXXXXX',
  STRIPE_PUBLIC_KEY: 'XXXXXXXX',
  CLIENT_PUBLIC_ID: 'XXXXX'
};

In modifyWebpackConfig I have some statements:

  1. I just have this "fixes" not to have broken references:
//https://github.com/request/request/issues/1529#issuecomment-90246518
config.externals = {
  fs: '{}',
  ajv: '{}',
  tls: '{}',
  net: '{}',
  console: '{}',
  child_process: '{}'
};
  1. It would be good idea to somehow support users who uses https://lernajs.io/. Because for each "package" I have statement like this for now:
config.resolve.modules.push(path.resolve(__dirname, "src/packages/SUB-PACKAGE/node_modules"));
config.resolveLoader.modules.push(path.resolve(__dirname, "src/packages/SUB-PACKAGE/node_modules"));

To make node_modules of sub-package be linked.

  1. Also in our project some directories are shared between projects. And other projects are not using css-modules, I needed to exclude shared-components folder from css-modules transformation:
//exclude /shared/ from css modules transformation
config.module.rules.push({
  test: /\.scss/,
  include: /shared/,
  use: [
	'style',
	{
	  loader: 'css',
	  options: { modules: false, sourceMap: true }
	},
	'postcss',
	'sass'
  ]
});
//for other components which is not in /shared/
config.module.rules.map((rule)=>{
  if (`${rule.test}`==="/\\.scss$/") {
	if (!rule.include) rule.exclude = /shared/;
  }
});
  1. Also, as a kyt convention, all files from /src will be included into bundle. It can be useful that users will have ability to include other dirs into bundle process. The similar way to browserify opts.paths .

  2. Kyt uses approach that tests should be written in filename.test.js. But a lot of users write tests in __tests__ folders. It can be useful to make this approach as an option in config, or put into recipes statement how to change this behavior.

No one mentioned file/font loaders yet. This is what currently is in my kyt.config.js:

  modifyWebpackConfig: (baseConfig, options) => {
    baseConfig.module.rules.push({
      test: /\.otf/,
      use: [{
        loader: "url-loader",
        options: {
          limit: 65000,
          mimetype: "application/x-font-opentype"
        }
      }]
    });
    return baseConfig;
  }

(Trying to reliably avoid flash of unstyled text in modern browsers and ensure fast loading speeds. If there‘s just one font including it with other site’s assets as opposed to using a CDN seems to be worth it, still in the process of figuring it out though.)

Found out this is needed when you want to run a starter kyt in a container (Docker in my case, but probably same is true for Vagrant).

module.exports = {
  reactHotLoader: true,
  debug: false,
  serverURL: 'http://0.0.0.0:3000',
  clientURL: 'http://0.0.0.0:3001',
}

Building a starter-kyt for a React, TypeScript, styled-components project. Working off of https://github.com/delambo/kyt-starter-universal-angular2

Currently having some issues because babel is not required with TS, but I'm still getting an ERROR in multi babel-polyfill webpack-hot-middleware error. Presumably, the JS file isn't being generated in time, or at all; but I'm not sure where babel-polyfill or HMR fits in here. I'm relatively new to webpack but I'm chipping away. Any resources would be helpful.

kyt.config.js:

module.exports = {
  reactHotLoader: false,
  debug: true,
  hasServer: false,
  modifyWebpackConfig: (config, options) => {
    config.resolve.extensions.push('.ts')
    config.resolve.extensions.push('.tsx')
    config.module.rules.push({
      test: /\.tsx?$/,
      exclude: [/\.(spec|e2e)\.tsx?$/, /node_modules/],
      loaders: ['ts-loader']
    })

    return config
  }
}
Jasu commented

Note: the changes below are not present in the latest release on NPM, but in the latest canary release 0.1.0-alpha.c0748b10.

We use this in druid-kyt-starter (via druid-kyt-default-configuration to

  • Add src/ to resolution paths so that import('../../../../../../comonents/Button'); is not necessary
  • Add __DEV__, __PROD__, __TEST__, __DEBUG__ defines
  • Change the Babel preset
  • Configure nodeExternals to use package.json instead of node_modules (to support Yarn workspaces). Also make it exclude react-universal-component so that it won't break.
  • Add support for universal rendering
    • Remove LimitChunkCountPlugin from client
    • Add generation of Webpack stats via StatsWriterPlugin and WriteFilePlugin
    • Add a CommonsChunkPlugin for a bootstrap.js chunk
    • Add a ContextReplacementPlugin to make import(`[universal]routes/${uriFromRequest}`); work without including .test.js files.
    • Replace ExtractTextPlugin with ExtractCssChunks plugin
    • Replace all CSS rules to replace ExtractTextPlugin with ExtractCssChunksPlugin and to remove style-loader.

I had to add code below to be able to use swaggergen-generated API classes (got the following error: "Module not found: Error Cannot resolve module")

if (baseConfig.module.rules) {
  baseConfig.module.rules.push({parser:{amd:false}});
}
return baseConfig;

I am adding graphql-tag loader and stage0

thank you!
Robert

I'm using it the add the Workbox plugin.

const WorkboxPlugin = require('workbox-webpack-plugin')

module.exports = {
  debug: false,
  modifyWebpackConfig: baseConfig => {
    baseConfig.plugins.push(
      new WorkboxPlugin.InjectManifest({
        swSrc: './src/public/sw.js',
      })
    )

    return baseConfig
  },
}

I'm using it to

  • load SVG the same way as janhoogeveen
  • define some config.resolve.alias for GSAP