easy-webpack / core

An easy way to create configuration files for Webpack
MIT License
68 stars 6 forks source link

Enhance the documentation for how to extend/overwrite configuration with custom values #13

Open Saeris opened 7 years ago

Saeris commented 7 years ago

In trying to resolve my issues getting Aurelia Webpack to run on OpenShift, I've come across an issue where I need to be able to create a proxy in Webpack devServer in order to handle websocket connections.

With the way easy-webpack is set up right now, there doesn't seem to be an easy way for me to pass in a proxy object to the devServer configuration. Maybe I'm just not understanding how to pass configuration objects to config-env-development properly (there seems to be a devtool option but it's not clear to me how to pass other settings). So assuming my problem isn't a lack of understanding, I would like to propose a solution similar to the following.

Since the metadata object in core is already being used for server configuration settings such as host and port, I would like it if you could also place proxy configuration objects there as well. Of course config-env-development and confog-env-production would need to be updated to use that configuration, since they handle the configuration of devServer itself.

Just for example, this is the configuration option I'm trying to pass to devServer but currently don't know how to do within easy-webpack:

proxy: {
    '/sockjs-node/*': {
        target: 'ws://localhost:8000',
        ws: true,
    },
},

┆Issue is synchronized with this Asana task

niieani commented 7 years ago

You can simply extend the config, in your case the devServer property, with your own configuration values. See the end of the example here, the commented out parts. I think adding proxies might be out of scope of config-env.

Does that solve your use-case?

Saeris commented 7 years ago

That doesn't seem to be working for me. Here's my config:


case 'development':
    process.env.NODE_ENV = 'development';
    config = generateConfig(
      baseConfig,

      require('@easy-webpack/config-env-development')
        ({devServer: {
          proxy: {
            '/sockjs-node/*': {
              target: 'ws://localhost:8000',
              ws: true,
            }
          } 
        }}),

    . . .

    );
    console.log(config);
    break;

And the generated config:

{ metadata:
   { port: 8080,
     host: '127.0.0.1',
     ENV: 'development',
     HMR: false,
     title: 'Saeris.io',
     baseUrl: '/',
     root: 'C:\\Users\\Saeris\\Documents\\GitHub\\saeris.io',
     src: 'C:\\Users\\Saeris\\Documents\\GitHub\\saeris.io\\src',
     extractTextInstances: Map { 'styles.css' => [Object] } },
  entry:
   { app: [ './src/main' ],
     'aurelia-bootstrap':
      [ './index',
        'aurelia-polyfills',
        'aurelia-pal',
        'aurelia-pal-browser',
        'regenerator-runtime',
        'bluebird' ],
     aurelia:
      [ 'aurelia-bootstrapper-webpack',
        'aurelia-binding',
        'aurelia-dependency-injection',
        'aurelia-event-aggregator',
        'aurelia-framework',
        'aurelia-history',
        'aurelia-history-browser',
        'aurelia-loader',
        'aurelia-loader-webpack',
        'aurelia-logging',
        'aurelia-logging-console',
        'aurelia-metadata',
        'aurelia-path',
        'aurelia-route-recognizer',
        'aurelia-router',
        'aurelia-task-queue',
        'aurelia-templating',
        'aurelia-templating-binding',
        'aurelia-templating-router',
        'aurelia-templating-resources' ] },
  output:
   { path: 'C:\\Users\\Saeris\\Documents\\GitHub\\saeris.io\\dist',
     filename: '[name].bundle.js',
     sourceMapFilename: '[name].bundle.map',
     chunkFilename: '[id].chunk.js' },
  debug: true,
  devtool: 'cheap-module-inline-source-map',
  devServer:
   { port: 8080,
     host: '127.0.0.1',
     historyApiFallback: true,
     watchOptions: { aggregateTimeout: 300, poll: 1000 },
     outputPath: 'C:\\Users\\Saeris\\Documents\\GitHub\\saeris.io\\dist' },
  plugins:
   [ HtmlWebpackPlugin { options: [Object] },
     ProvidePlugin { definitions: [Object] },
     ProvidePlugin { definitions: [Object] },
     ProvidePlugin { definitions: [Object] },
     ExtractTextPlugin { filename: 'styles.css', id: 1, options: [Object] },
     AureliaWebpackPlugin { options: [Object] },
     DefinePlugin { definitions: [Object] } ],
  resolve:
   { root: 'C:\\Users\\Saeris\\Documents\\GitHub\\saeris.io\\src',
     modules:
      [ 'C:\\Users\\Saeris\\Documents\\GitHub\\saeris.io\\src',
        'node_modules' ] },
  module:
   { loaders:
      [ [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object] ] } }

Maybe I'm just still not understanding your documentation correctly?

niieani commented 7 years ago

Like this:


case 'development':
    process.env.NODE_ENV = 'development';
    config = generateConfig(
      baseConfig,

      require('@easy-webpack/config-env-development')
        (),

      {
        devServer: {
          proxy: {
            '/sockjs-node/*': {
              target: 'ws://localhost:8000',
              ws: true,
            }
          } 
        }
      }
    . . .

    );
    console.log(config);
    break;
Saeris commented 7 years ago

Okay, that seems to be working correctly. It wasn't entirely clear to me by your documentation that I had to pass custom configuration objects like that. I was trying to pass it as an argument to config-env-development, not append the result it generates.

Thank you for the help!

niieani commented 7 years ago

Would you have suggestions as to how correct the documentation to make it clearer? Even better, I'd love a pull request if you'd have a moment. Many thanks!

Saeris commented 7 years ago

I would feel more comfortable making a pull request and touching up the documentation if I had a better idea of what I was doing. I'm basically your target audience. Before picking up Aurelia I had never used Webpack before, so everything about it is new to me and there's a ton of things I don't yet understand about it. Easy-webpack is valuable to me because it does take care of a lot of work for me so I can spend less time configuring my builds and more time developing my applications.

But given the nature of all of this being cutting edge and constantly changing I'm still having to learn a lot about it, often without any prior examples to work off of, I'm stuck digging deep into webpack on top of everything else. As I come to understand both webpack and your code better, perhaps I'll be better suited to document how it works to a less technical crowd.

What I got from this was a bit of a better understanding of how easy-webpack takes raw and generated config objects and combines them together. That merger process didn't quite click for me. This is how I understand the steps that are happening now:

Take the baseConfig object, now generate a devServer object using config-env-development, then overwrite/append that generated devServer object with the properties of {customConfigObj}, etc.

See the confusing part for me, especially with your commented code, was when I see

require('@easy-webpack/config-env-development')
        ({devtool: 'inline-source-map'}),

in my webpack.config.js from Aurelia Navigation Skeleton, then

// feel free to add your own overrides, custom plugins, add your own options... e.g.:
// { plugins: [ new CustomPlugin() ] }, // <-- appends a plugin
// { devtool: 'inline-source-map' },    // <-- replaces the devtool
// function () { return { debug: !this.debug } } // <-- uses previous value to compute the new one

in your documentation, my first thought is to try and pass { devtool: 'inline-souce-map' } as an argument to config-env-development as I've seen elsewhere in the code. My first thought to verify whether this was the correct usage of that function was to look at the source code for it. Wherein I see this:

export = function development({devtool = 'cheap-module-inline-source-map'} = {}) {
  return function development(this: WebpackConfig): WebpackConfig {
    return {
      debug: true,
      devtool,
      // devtool: 'eval',
      // devtool: 'cheap-module-source-map',
      // devtool: 'eval-source-map',
      /**
       * Options affecting the output of the compilation.
       *
       * See: http://webpack.github.io/docs/configuration.html#output
       */

I wasn't quite sure what I was looking at because unlike some of your other plugins (such as config-sass), there were no comments on how those arguments are used.

Does any of that make sense? I'm trying to give you a better idea of my troubleshooting process and how I'm trying to learn your code. I don't have any experience writing typescript and I'm not at the same level of es6/javascript understanding as you are. So I don't always know the technical intricacies of what I'm looking at.

niieani commented 7 years ago

Thanks. I've changed the name of the issue to better reflect what needs to be done.

Saeris commented 7 years ago

Cool. I hope this helps you and others out!

To add to what I said above, my natural inclination when using easy-webpack is to assume that any of the plugins should handle a whole part of generating a config object for me. So anytime I see one of them being passed arguments, I assume that there's something I can customize about what that plugin is returning to me (such as in the case of config-sass). I don't immediately think that it's going to return a "mostly complete" config that I'll then need to overwrite (because then what's the point of those plugins if I'm just going to have to write the config myself?). So yes, as in your documentation, order matters, because sometimes you have to generate a partial config then overwrite/append the results to fill in the gaps like here in my use case.

I originally filed this issue because I thought it would be useful to add support to keep code DRY. It makes sense to me to define your proxy values once and have the plugins that handle devServer configuration to know to use those values. While this isn't a big deal for me, the solution to my problem was simple enough, I just think in a larger project this could be of use to people.

niieani commented 7 years ago

The thing is, your use-case is not very common, as most people won't need proxies - but I'll be willing to add support to config-env's at some point. The override / add on top functionality is there for exactly those reasons - you get nice defaults from the preset configs which you can add to later on.

Thanks for taking the time to explain!

Saeris commented 7 years ago

Probably true. I'm still having issues with my specific use-case (OpenShift sounded great on paper, but I'm starting to wonder if free nodejs hosting is worth all these headaches. Yay incomplete documentation!), but this did help point me in the right direction I think.