Skip to content

Instantly share code, notes, and snippets.

@jescalan
Last active May 8, 2017 18:25
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jescalan/8e39596765c66a192d00c2684437bf57 to your computer and use it in GitHub Desktop.
Save jescalan/8e39596765c66a192d00c2684437bf57 to your computer and use it in GitHub Desktop.
Spike v1 Migration Guide

Spike v1 Migration Guide

Spike v1 represents a significant change, mostly because it includes an update from webpack v1 to webpack v2 behind the scenes. The aim of this piece is to guide you through the process of migration from one version to the next, and explain a bit of the rationale behind these changes.

App.js Updates

The bulk of the migration work lies in the app.js file. Webpack drastically changed its configuration in a very breaking manner between v1 and v2, so spike was forced to do the same, since spike is an extension of webpack.

Webpack Config Changes

Any webpack-specific config you had in an app.js file might be affected. Most likely, it will be the change from module.loaders to module.rules. See the webpack docs for details on all changed webpack properties.

Reshape, Postcss Config Changes

The way that the reshape and postcss config keys work has slightly changed. Where in pre-v1 spike configs, you might have something like this:

module.exports = {
  // ...other config...
  reshape: (ctx) => {
    return htmlStandards({
      webpack: ctx,
      locals: { pageId: pageId(ctx), foo: 'bar' }
    })
  },
  postcss: (ctx) => {
    return cssStandards({ webpack: ctx })
  }
}

...to work with v1, it would need to change as such:

module.exports = {
  // ...other config...
  reshape: htmlStandards({
    locals: (ctx) => { return { pageId: pageId(ctx), foo: 'bar' } }
  }),
  postcss: cssStandards()
}

Basically, if you need to pass a function that gets the loader context, the function needs to move from the overall reshape key into specific properties, and the webpack config key can be completely removed for all configurations. The reshape and postcss keys must receive an object, and not a function. You will get an error if either of these keys receive a function, and it will be a really long, confusing webpack error.

Hard Source Plugin Removed

If you were using the hard source webpack plugin, which was previously in the default configuration, we would strongly advise removing it as part of your upgrade process. While the plugin has huge potential for enabling incremental builds, it's not quite stable enough at the moment as a spike integration to be a recommendation, and has caused a number of issues in the past. It's even less compatible with the v2 upgrade, so it's time to move on. You can remove this plugin from your config and package.json file.

Recommended: Babel Config Update

Babel has rolled out a new fantastic preset called babel-preset-env which gives you an up-to-date version of es6 and additonal options to tailor babel's features to the browsers you support. In addition, webpack2 supports es modules and tree-shaking, so we want to turn off babel's ES module compilation, and enable support for the raw import function which webpack can use to interactively code split dependencies. If your old babel config looked like this:

const jsStandards = require('babel-preset-latest')

module.exports = {
  // ...other config...
  babel: { presets: [jsStandards] },
}

...your new one should look more like this:

const jsStandards = require('babel-preset-env')
const dynamicImport = require('babel-plugin-syntax-dynamic-import')

module.exports = {
  // ...other config...
babel: { presets: [[jsStandards, { modules: false }]], plugins: [dynamicImport] }
}

And don't forget to uninstall previous babel presets and install babel-preset-env and babel-plugin-syntax-dynamic-import as well:

yarn remove babel-preset-latest && yarn add babel-preset-env babel-plugin-syntax-dynamic-import

Dependency Updates

The following spike dependencies need to be updated to the latest version in order to work with spike v1:

  • reshape-standard
  • spike-css-standards
  • spike-page-id
  • spike-records
  • spike-contentful
  • spike-collections
  • reshape-include
  • reshape-layouts
  • reshape-loader
  • spike-util

Any of these left at previous versions will break your project. You can run yarn upgrade-interactive to quickly select upgrades.

The following plugins have not yet received updates, and are in progress. Any help appreciated!

  • spike-rooftop
  • spike-pushstate

Custom Plugin Updates

If you have a custom spike plugin, it will need a couple small adjustments in order to work with v1 of spike. Primarily, if you were accessing any spike options from compiler.options.spike, or accessing compiler.options.reshape|babel|postcss -- basically any property that is not listed explicitly in webpack's docs, you will need to access it in a different way, since webpack strictly validates configs in v2. Any other properties that spike uses are able to be accessed using a little hack spike uses internally to bypass webpack's validation, abstracted into a util method.

To get these options, just install spike-util, initialize it, and use the getSpikeOptions() method.

const SpikeUtil = require('spike-util')

module.exports = class MyPlugin {
  apply (compiler) {
    const util = new SpikeUtil(compiler.options)
    consolel.log(util.getSpikeOptions())
  }
}

This is the only major update to plugins, other than the standard range of webpack config updates linked above in their migration guide.

Javascript Updates

Webpack 2 supports es modules and tree shaking, which is exciting, and you should take advantage of this in your client-side scripts. Now, instead of commonjs you can use es6 module syntax directly (so long as you made the recommended babel config update seen above, or started a new project with the default template).

// you should use this now
import something from 'something'
// NOT this anymore
const something = require('something')

In addition, webpack will dynamically code split and load modules on demand if you use import as a function. So for example:

if (noSupportForPromises) {
  import('promise-polyfill').then((mod) => console.log(mod))
}

This code would only load in a fictional promise polyfill if the condition is matched. The import function returns a promise that receives the module's default export. Pretty cool!

Get Support!

If you are still running into errors or having issues upgrading, come by our gitter channel where a friendly member of the community will surely be able to offer assistance. Thanks for sticking with us, and hope you enjoy the upgrade!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment