Skip to content

Option to install or export default webpack config from @rails/webpacker? #794

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jnfeinstein opened this issue Sep 13, 2017 · 5 comments
Closed

Comments

@jnfeinstein
Copy link

jnfeinstein commented Sep 13, 2017

Greetings,

I just upgraded webpacker from v2 to v3 (fastest moving rails lib I know of!). One of the notable changes is that the configuration/loaders/plugins are all managed by @rails/webpacker. I'm guessing this was done such that the gem and configurations stay in sync (i.e. at 3.0.1, both look to webpacker.yml for configuration, but this may change in the future). Makes a great deal of sense and it's a nifty feature.

My Angular 1 application has a bunch of custom configuration, such as a custom loader and the ngAnnotate plugin. The best I could come up with in webpacker v3 world was:

const babelLoader = environment.loaders.get('babel')
babelLoader.use = [
  // Trying to maintain the default behavior, I trust the gurus of webpacker know better than I do
  { loader: babelLoader.loader, options: babelLoader.options },
  { loader: join(__dirname, 'utils', 'angular-loader.js') }
];
delete babelLoader.options;
delete babelLoader.loader;

and (since plugin order matters)

const UglifyJsPlugin = environment.plugins.get('UglifyJs');
environment.plugins.delete('UglifyJs');

environment.plugins.set(
  'ngAnnotate',
  new ngAnnotatePlugin({
    add: true
  })
);

Object.assign(UglifyJsPlugin, {
  mangle: true,
  sourceMap: false
});

environment.plugins.set('UglifyJs', UglifyJsPlugin);

To an extent these defeat the purpose of having the default configuration package, since they rely on the configuration being consistent. babelLoader has to exist, otherwise my angular loader wont be installed properly, but AFAIK the internals of @rails/webpacker don't necessarily adhere to any API. I also don't trust maps to be ordered, so that's not an ideal data structure for a feature where order matters.

My gut reaction was to just go back to my v2 configuration, which gave me the ultimate flexibility in configuration, but I don't know if anything was changed w/ regards to binding to the gem in v3 (like did the format of webpacker.yml change?).

Options I can think of (that may already exist and I'm unaware of):

  • Copy the default configuration files present in @rails/webpacker to config/webpacker so I can manipulate them manually. Whenever I bump the gem version I can regenerate these files and diff them. I do this often for other packages.
  • Export a core API from @rails/webpacker. For example, in v2 configuration.js had const configPath = resolve('config', 'webpacker.yml'). This could be imported as const { configPath } = require('@rails/webpacker/paths'). With this I could write my own config that ties into the gem, but still offers maintainers flexibility.

A combination of both would presumably be best, generate a default configuration that ties into an API exported by @rails/webpacker.

Thanks for helping on this issue!

@earnubs
Copy link
Contributor

earnubs commented Sep 15, 2017

You can require config directly (but perhaps a named export from @rails/webpacker would be more robust):

const config = require('@rails/webpacker/package/config');

And on plugins, have a look at webpack-merge, for example this would replace the default Uglify with latest:

// ./config/webpack/production.js

const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const merge = require('webpack-merge');

module.exports = merge({
  customizeArray: merge.unique(
    'plugins',
    ['UglifyJsPlugin'],
    plugin => plugin.constructor && plugin.constructor.name
  )
})({
  plugins: [
    new UglifyJsPlugin({
      parallel: true,
      sourceMap: true
    })
  ]
}, environment.toWebpackConfig());

Alteratively, you could move the webpack-merging for each env to your own webpack config folder, and import the defaults from config/webpack/ (meaning less conflicts to deal with on upgrade), then change WEBPACK_CONFIG in the binstubs (I haven't tried that though).

@jnfeinstein
Copy link
Author

jnfeinstein commented Sep 15, 2017

If I'm not mistaken this still relies on the remote package. I'd like to have full control in my local project so I know what's being used where (and easily modified).

Is require('@rails/webpacker/package/config'); the root of the default config? I could copy that to my local project. The most sustainable way would be using a rake task that could point at the correct location. I'm imagining sort of like the webpacker:install task where it asks you about each conflicting file (webpacker:install_config).

Looks like all the necessary files are included with the gem, so this would be pretty easy.

@gauravtiwari
Copy link
Member

#884 is now merged - please see PR for docs

@jnfeinstein
Copy link
Author

jnfeinstein commented Nov 16, 2017

#884 solves the order issue, very helpful.

I still feel that adding an API around webpack config is an over-complication (#895). Webpack config is rather complex as it is, wrapping it in an API adds further complication. It also means that maintainers of this package will have to provide support for said API and handle additional issues as they arise, which I'm guessing will mostly be "how can I configure weird thing XYZ in webpacker?"

I'm using the config from v2 in production, it's working quite well.

@gauravtiwari
Copy link
Member

gauravtiwari commented Nov 17, 2017

Great 👍

Ahh right, the new API's are there to make life easy when setting values on config object but environment.config basically returns the same config object as webpack so, you can merge in new properties are you would do in version 2 using webpack-merge. I would encourage to try it out and feel free to report any problems encountered :).

const environment = require('@rails/webpacker')

environment.config = // {} webpack config object

environment.config.set('resolve.extensions', ['.foo', '.bar'])
environment.config.set('output.filename', '[name].js')
environment.config.delete('output.chunkFilename')
environment.config.get('resolve')

// Just merge as you would do with webpack-merge
environment.config.merge({ output: {
    filename: '[name].js'
  }
})

We will document these and hopefully this will solve most of the cases out of the box.

The major problem with v2 config was that whenever we changed anything inside Gem the user has to run installer, which probably wasn't the best experience and folks ran into gotchas when they didn't had the most up to date config.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants