Javascriptservices: Consider moving webpack config files to a /config directory

Created on 12 Jul 2016  路  5Comments  路  Source: aspnet/JavaScriptServices

The root directory of the React/Redux template is getting quite messy.
Not all the files there have to be in the root.
The webpack config files could be moved to a /config or /webpack directory.

enhancement P2

Most helpful comment

@SteveSandersonMS

At the very least, it would need to support running webpackfrom the project root

Would you be open to npm scripts instead?

Something like this perhaps:

  "scripts": {
    "build": "npm run build:vendor && npm run build:main",
    "build:main": "webpack --config ./config/webpack.config.js",
    "build:vendor": "webpack --config ./config/webpack.config.vendor.js",
  }

Usage:
npm run build:vendor

which IMO is nicer than:
webpack --config webpack.config.vendor.js

You can still pass args to webpack like:
npm run build:vendor -- --display-modules

This has a couple other added benefits:

  1. The npm scripts can be invoked from VS 2015's "Task Runner Explorer" pane by using this extension. Further, they can be bound to build events.
  2. Eliminates the need for a global installation of webpack

...and all relative paths in configs anywhere should be interpreted as relative to the file from which they are being referenced.

Taking a page from create-react-app (after npm run eject), they use absolute paths in the configs:

They set them up in paths.js:
https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/config/paths.js#L38

Then in our webpack.config.js for example:

var paths = require('./paths');
...
...
...
    plugins: [
        extractCSS,
        new webpack.DllReferencePlugin({
            context: '.',
            manifest: require(path.join(paths.wwwRoot, 'dist', 'vendor-manifest.json'))
        })

I have all this working with a couple other changes that are required.

Personally, I find it "sufficiently clean and confusion-proof." What are your thoughts?

All 5 comments

As proposed, this has now been considered :)

Having the configs in some non-root directory introduces extra possible confusions:

  • You can't just run webpack at your project root (or at least, doing so will produce unexpected behavour because of the lack of webpack.config.js in that dir). Or to enable that, we'd have to have some 'wrapper' webpack.config.js at the root that knows how to invoke other Webpack configs, which is not itself a native feature of Webpack (though I wish it was (and no, using require to reference one config from another is not a good solution, as it changes the meaning of paths)).
  • If your webpack.config.js is in a non-project-root location, then any paths that it references will be resolved relative to different directories depending on whether they are just given as a string (like ./boot-client.ts) versus whether they are 'required' (like require('../wwwroot/dist/vendor-manifest.json')). Trying to set this up in a non-root dir, I got confused about what the correct paths were several times - I'm pretty sure people unfamiliar with Webpack and how require works would get extremely confused.

So, if someone is able to come up with a sufficiently clean and confusion-proof way of having the configs at a non-root location, please let us know! At the very least, it would need to support running webpack from the project root, and all relative paths in configs anywhere should be interpreted as relative to the file from which they are being referenced.

In the absence of a good solution, I don't think this is something we should do.

@SteveSandersonMS

At the very least, it would need to support running webpackfrom the project root

Would you be open to npm scripts instead?

Something like this perhaps:

  "scripts": {
    "build": "npm run build:vendor && npm run build:main",
    "build:main": "webpack --config ./config/webpack.config.js",
    "build:vendor": "webpack --config ./config/webpack.config.vendor.js",
  }

Usage:
npm run build:vendor

which IMO is nicer than:
webpack --config webpack.config.vendor.js

You can still pass args to webpack like:
npm run build:vendor -- --display-modules

This has a couple other added benefits:

  1. The npm scripts can be invoked from VS 2015's "Task Runner Explorer" pane by using this extension. Further, they can be bound to build events.
  2. Eliminates the need for a global installation of webpack

...and all relative paths in configs anywhere should be interpreted as relative to the file from which they are being referenced.

Taking a page from create-react-app (after npm run eject), they use absolute paths in the configs:

They set them up in paths.js:
https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/config/paths.js#L38

Then in our webpack.config.js for example:

var paths = require('./paths');
...
...
...
    plugins: [
        extractCSS,
        new webpack.DllReferencePlugin({
            context: '.',
            manifest: require(path.join(paths.wwwRoot, 'dist', 'vendor-manifest.json'))
        })

I have all this working with a couple other changes that are required.

Personally, I find it "sufficiently clean and confusion-proof." What are your thoughts?

That's a great idea, and is definitely what we can recommend to anyone who wants to move their webpack config files, or more generally anyone who's ready to set up custom build scripts.

As for whether to make it a default, let's keep a lookout for how much people tell us they're doing things along these lines. There is the slight drawback that by hiding webpack behind npm, it becomes harder for developers new to these tools to really understand what they are doing, and docs/tutorials they might read about Webpack would need extra translation into this scenario. It's a tricky balance to strike.

So, anyone who wants this setup can move to it pretty easily based on your instructions, and as for total newcomers, hopefully the fact that we've recently reduced the number of Webpack config files from 4 down to 2 makes this less of a concern. Sounds reasonable?

One thing that might definitely be worth adding is a postinstall to the default templates? It seems sometimes people pull down fresh repos and the yeoman process somehow doesn't run the webpack vendor event. What do you think?

"postinstall" : "webpack --config ./config/webpack.config.vendor.js"

We'll need to avoid postinstall steps because these templates are going to be used to generate Visual Studio templates as well as Yeoman ones, and I've been told we shouldn't expect the VS tooling to support postinstall actions.

It seems sometimes people pull down fresh repos and the yeoman process somehow doesn't run the webpack vendor event

If there is a problem with that, we need to understand and solve the underlying problem! Things cannot be allowed to behave randomly :)

Was this page helpful?
0 / 5 - 0 ratings