Giter Club home page Giter Club logo

webpack-blocks's Introduction

webpack-blocks

Build Status Gitter chat

Functional building blocks for your webpack config: easier way to configure webpack and to share configuration between projects.

Ready to use blocks to configure popular tools like Babel, PostCSS, Sass, TypeScript, etc., as well as best practices like extracting CSS β€” all with just one line of configuration.

Note: This is the documentation of webpack-blocks v2, compatible with webpack 4. Check out the v1 branch if you need to be compatible with webpack 3 or older.

"Finally, webpack config done right. (...) Webpack clearly wants to stay low-level. So it makes total sense to outsource configuring it to well designed blocks instead of copy-paste."

Dan Abramov via twitter (Co-author of Redux, Create React App and React Hot Loader)

Table of contents

Installation

npm install --save-dev webpack webpack-blocks
# or
yarn add --dev webpack webpack-blocks

Example

The following sample shows how to create a webpack config with Babel support, dev server and Autoprefixer.

const webpack = require('webpack')
const {
  createConfig,
  match,

  // Feature blocks
  babel,
  css,
  devServer,
  file,
  postcss,
  uglify,

  // Shorthand setters
  addPlugins,
  setEnv,
  entryPoint,
  env,
  setOutput,
  sourceMaps
} = require('webpack-blocks')
const autoprefixer = require('autoprefixer')
const path = require('path')

module.exports = createConfig([
  entryPoint('./src/main.js'),
  setOutput('./build/bundle.js'),
  babel(),
  match(['*.css', '!*node_modules*'], [
    css(),
    postcss({
      plugins: [
        autoprefixer({ browsers: ['last 2 versions'] })
      ]
    })
  ]),
  match(['*.gif', '*.jpg', '*.jpeg', '*.png', '*.webp'], [
    file()
  ]),
  setEnv({
    NODE_ENV: process.env.NODE_ENV
  }),
  env('development', [
    devServer(),
    devServer.proxy({
      '/api': { target: 'http://localhost:3000' }
    }),
    sourceMaps()
  ]),
  env('production', [
    uglify(),
    addPlugins([new webpack.LoaderOptionsPlugin({ minimize: true })])
  ])
])

See shorthand setters and helpers documentation.

All blocks, like babel or postcss are also available as their own small packages, webpack-blocks package wraps these blocks, shorthand setters and helpers as a single dependency for convenience.

More examples

CSS modules:

const { createConfig, match, css } = require('webpack-blocks')

// ...

module.exports = createConfig([
  // ...
  match(['*.css', '!*node_modules*'], [
    css.modules()
  ]
])

TypeScript:

const { createConfig } = require('webpack-blocks')
const typescript = require('@webpack-blocks/typescript')

// ...

module.exports = createConfig([
  // ...
  typescript()
])

Custom blocks

Need a custom block? A simple block looks like this:

module.exports = createConfig([
  // ...
  myCssLoader(['./styles'])
])

function myCssLoader() {
  return (context, { merge }) =>
    merge({
      module: {
        rules: [
          Object.assign(
            {
              test: /\.css$/,
              use: ['style-loader', 'my-css-loader']
            },
            context.match // carries `test`, `exclude` & `include` as set by `match()`
          )
        ]
      }
    })
}

If we use myCssLoader in match() then context.match will be populated with whatever we set in match(). Otherwise there is still the test: /\.css$/ fallback, so our block will work without match() as well.

Check out the sample app to see a webpack config in action or read how to create your own blocks.

Available webpack blocks

Helpers allow you to structure your config and define settings for particular environments (like production or development) or file types.

  • group
  • env
  • match
  • when

Shorthand setters gives you easier access to common webpack settings, like plugins, entry points and source maps.

  • addPlugins
  • customConfig
  • defineConstants
  • entryPoint
  • performance
  • resolve
  • setContext
  • setDevTool
  • setEnv
  • setOutput
  • sourceMaps

Third-party blocks

Missing something? Write and publish your own webpack blocks!

Design principles

  • Extensibility first
  • Uniformity for easy composition
  • Keep everything configurable
  • But provide sane defaults

FAQ

How to debug?

In case the webpack configuration does not work as expected you can debug it using q-i:

const { print } = require('q-i')

module.exports = createConfig([
  // ...
])

print(module.exports)
How does env() work?

env('development', [ ... ]) checks the NODE_ENV environment variable and only applies its contained webpack blocks if it matches the given string.

So make sure you set the NODE_ENV accordingly:

// your package.json
"scripts": {
  "build": "cross-env NODE_ENV=production webpack",
  "start": "cross-env NODE_ENV=development webpack-dev-server"
}

If there is no NODE_ENV set then it will treat NODE_ENV as if it was development. Use cross-env to make it work on all platforms.

What does defineConstants() do?

defineConstants() is a small convenience wrapper around webpack's DefinePlugin. It is composable and automatically encodes the values. Use it to replace constants in your code by their values at build time.

So having a defineConstants({ 'process.env.FOO': 'foo' }) and a defineConstants({ 'process.env.BAR': 'bar' }) in your config means the resulting webpack config will contain a single new webpack.DefinePlugin({ 'process.env.FOO': '"FOO"', 'process.env.BAR': '"BAR"' }), thus replacing any occurrence of process.env.FOO and process.env.BAR with the given values.

You can also use setEnvΒ method to define process.env.* variables, it’s based on webpack.EnvironmentPlugin: setEnv({ FOO: 'foo' }).

What does a block look like from the inside?

A webpack block is a function and requires no dependencies at all (πŸŽ‰πŸŽ‰), thus making it easy to write your own blocks and share them with your team or the community.

Take the babel webpack block for instance:

/**
 * @param {object} [options]
 * @param {RegExp|Function|string}  [options.exclude]   Directories to exclude.
 * @return {Function}
 */
function babel(options = { cacheDirectory: true }) {
  return (context, util) =>
    util.addLoader(
      Object.assign(
        {
          // we use a `MIME type => RegExp` abstraction here in order to have consistent regexs
          test: /\.(js|jsx)$/,
          exclude: /node_modules/,
          use: [{ loader: 'babel-loader', options }]
        },
        context.match
      )
    )
}

Add a README and a package.json and you are ready to ship.

For more details see How to write a block.

I need some custom webpack config snippet!

No problem. If you don't want to write your own webpack block you can use customConfig():

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { addPlugins, customConfig } = require('@webpack-blocks/webpack')

// ...

module.exports = createConfig([
  // ...
  addPlugins([
    // Add a custom webpack plugin
    new HtmlWebpackPlugin({
      inject: true,
      template: './index.html'
    })
  ]),
  customConfig({
    // Add some custom webpack config snippet
    resolve: {
      extensions: ['.js', '.es6']
    }
  })
])

The object you pass to customConfig() will be merged into the webpack config using webpack-merge like any other webpack block's partial config.

How to compose blocks?

Got some projects with similar, yet not identical webpack configurations? Create a β€œpreset”, a function that returns a group of blocks so you can reuse it in multiple projects:

const { createConfig, env, group, babel, devServer } = require('webpack-blocks')

function myPreset(proxyConfig) {
  return group([babel(), env('development', [devServer(), devServer.proxy(proxyConfig)])])
}

module.exports = createConfig([
  myPreset({
    '/api': { target: 'http://localhost:3000' }
  })
  // add more blocks here
])

The key feature is the group() method which takes a set of blocks and returns a new block that combines all their functionality.

Like what you see?

Support webpack-blocks by giving feedback, contributing to this repository, publishing new webpack blocks or just by 🌟 starring the project!

Contributors

These awesome people have helped webpack-blocks by adding features, fixing bugs and refactoring code. You can become one of them!

License

MIT

webpack-blocks's People

Contributors

aaronjensen avatar adamdicarlo avatar amilajack avatar andywer avatar azat-io avatar boxfoot avatar davidnguyen11 avatar dependabot[bot] avatar diegohaz avatar dmitmel avatar dmitriz avatar exon avatar geczy avatar jaronheard avatar jeetiss avatar jermspeaks avatar julienmartin avatar jvanbruegge avatar langovoi avatar marcofugaro avatar pravdomil avatar sapegin avatar smdern avatar soda-x avatar timdeschryver avatar tommmyy avatar vlad-zhukov avatar zcei avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

webpack-blocks's Issues

Warn if first argument in createConfig is not of type array

I made the mistake to not put the config in an array, the result was that I wasted at least half an hour debugging the result of createConfig. It'd be nice for DX to add a warning for this :).

I do wonder why createConfig expects an array though, because it seems that there's only one argument, so wouldn't it be better to just spread the arguments or use the arguments variable (if older version of Node should be supported)?

Errors when running test-app

> @ start /Users/dmitrizaitsev/Repos/webpack-blocks/test-app
> NODE_ENV=development webpack-dev-server --config webpack.config.babel.js

/Users/dmitrizaitsev/Repos/webpack-blocks/test-app/node_modules/@webpack-blocks/babel6/index.js:22
          test: fileTypes('application/javascript'),
                ^

TypeError: fileTypes is not a function
    at /Users/dmitrizaitsev/Repos/webpack-blocks/test-app/node_modules/@webpack-blocks/babel6/index.js:22:17
    at /Users/dmitrizaitsev/Repos/webpack-blocks/test-app/node_modules/@webpack-blocks/core/src/index.js:94:29
    at Array.reduce (native)
    at invokeConfigSetters (/Users/dmitrizaitsev/Repos/webpack-blocks/test-app/node_modules/@webpack-blocks/core/src/index.js:92:24)
    at Object.createConfig (/Users/dmitrizaitsev/Repos/webpack-blocks/test-app/node_modules/@webpack-blocks/core/src/index.js:33:18)
    at createConfig (/Users/dmitrizaitsev/Repos/webpack-blocks/test-app/node_modules/@webpack-blocks/webpack2/index.js:41:15)
    at Object.<anonymous> (/Users/dmitrizaitsev/Repos/webpack-blocks/test-app/webpack.config.babel.js:11:18)
    at Module._compile (module.js:570:32)
    at loader (/Users/dmitrizaitsev/Repos/webpack-blocks/test-app/node_modules/babel-register/lib/node.js:144:5)
    at Object.require.extensions.(anonymous function) [as .js] (/Users/dmitrizaitsev/Repos/webpack-blocks/test-app/node_modules/babel-register/lib/node.js:154:7)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)
    at requireConfig (/Users/dmitrizaitsev/Repos/webpack-blocks/test-app/node_modules/webpack/bin/convert-argv.js:97:18)

npm ERR! Darwin 12.6.0
npm ERR! argv "/usr/local/bin/node" "/Users/dmitrizaitsev/.npm-global/bin/npm" "start"
npm ERR! node v6.9.2
npm ERR! npm  v4.0.5
npm ERR! code ELIFECYCLE
npm ERR! @ start: `NODE_ENV=development webpack-dev-server --config webpack.config.babel.js`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the @ start script 'NODE_ENV=development webpack-dev-server --config webpack.config.babel.js'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the  package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     NODE_ENV=development webpack-dev-server --config webpack.config.babel.js
npm ERR! You can get information on how to open an issue for this project with:
npm ERR!     npm bugs 
npm ERR! Or if that isn't available, you can get their info via:
npm ERR!     npm owner ls 
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     /Users/dmitrizaitsev/Repos/webpack-blocks/test-app/npm-debug.log

webpack-merge or not?

Right now webpack-blocks is using webpack-merge to merge the blocks' config snippets to a complete config object.

There are some problems with webpack-merge, though:

  • It is designed to concatenate/extend config objects/properties/arrays, but it is a problem to clear an object that's part of the webpack config that has been set before.
  • An array might be cleared by passing an empty array to the merge function. But this causes another issue: You wouldn't expect that merging an empty array clears all existing items.

The webpack-merge makers are already discussing the issue (survivejs/webpack-merge#45), but I am not a big fan of the proposed approach.

Possible solution: Use https://github.com/kolodny/immutability-helper instead of webpack-merge altogether.

Open for discussion :)

Block internals: Pre- and post-processing hooks

As @eXon pointed out in #17 it might be beneficial to enable webpack blocks to define post-processing functions. That could allow you to define constants multiple times in multiple blocks, but eventually get a single webpack.DefinePlugin instance.

Another use case is the dev-server block which is currently being changed (#21). It adds a dev-server entry point to every chunk in the entry object. Right now this means that the dev-server is used after setting all your entry points. A post-processing step defined by dev-server would allow you to use your entry and dev-server blocks in random order.

A pre-processing might be desirable to add custom mime types before any the blocks are run.

Open for discussion :)

Add end-to-end testing

Right now there are unit tests and an integration test that tests the interaction between the packages.

There shall be tests for not only creating a config, but actually make webpack run them!

API: Array argument vs. many arguments

This is the discussion for the API syntactics suggestion which started in #24.

How it works now

createConfig([
  block1(),
  block2(),
  block3()
])

Alternative

createConfig(
  block1(),
  block2(),
  block3()
)

The question

Are there strong feelings towards one of the syntaxes or another? This affects createConfig(), env() and (not yet implemented) group().

@eXon @andreiglingeanu

@easy-webpack: Same idea, similar execution

Hi @andywer,

I'm the author of easy-webpack, which, from the looks of it seems like the same idea as webpack-blocks, just executed by a different person. Am I correct in assuming you weren't aware of my project in July 2016 and thus started your own, or was there something about @easy-webpack that didn't satisfy your needs?

Looking through your project I saw some overlapping issues between our projects: the latest design of @easy-webpack uses a different solution to the ones proposed in #34, I've been struggling with the 'best design' for this myself.

Being the default configurator for the @aurelia framework, we also had some user complaints about how 'blackboxed' the configs are (i.e. it takes an effort to take them out when you reach a point a 'preset' is not enough; I imagine it's the same with webpack-blocks), so I had some thoughts on how to mitigate this for v3 of @easy-webpack by simply inlining the generated configs with a sort of virtual 'git' repository, marking edges of inlined presets in comments. I've also recently thought of a different concept for conditional configuration, like this, but I'm still thinking about the best way to solve both of these.

Would combining efforts make sense to you?

Support for react-hot loader

Right now there is no support for the react-hot loader : https://github.com/gaearon/react-hot-loader

Basically what you need is the devServer enabled (already got the block for that) and the 'react-hot' loader before the 'babel-loader'.

Right now, I'm doing (first loader is babel in my case):

module.exports.module.loaders[0].loaders.unshift('react-hot');

Is there a better way to do that in a non-hackish way?

`env()` should pass `config` to setters, but not merge it already

env() returns a setter function (basically a block). This function receives the merge-in-progress config like any other block and that's fine.

But: It calls invokeConfigSetters() which is not only merging the env()'s blocks, but also the config passed by createConfig(), thus the result of env() has already merged all previous config into the webpack config snippet it returns.

Result: Duplicate stuff in the snippet created by env().
Seems not be very critical, but it is a bug and might lead to unexpected behavior.

Webpack 2 + PostCSS errors (Invalid configuration object ...)

I have tested webpack.config.js exactly as in
https://github.com/andywer/webpack-blocks#usage
which lead to errors:

Β± |master βœ“| β†’ npm run build

> [email protected] build /Users/dmitrizaitsev/Dropbox/Sandbox/webpack2-blocks-test
> webpack

Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
 - configuration has an unknown property 'postcss'. These properties are valid:
   object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry, externals?, loader?, module?, name?, node?, output?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, stats?, target?, watch?, watchOptions? }
   For typos: please correct them.
   For loader options: webpack 2 no longer allows custom properties in configuration.
     Loaders should be updated to allow passing options via loader options in module.rules.
     Until loaders are updated one can use the LoaderOptionsPlugin to pass these options to the loader:
     plugins: [
       new webpack.LoaderOptionsPlugin({
         // test: /\.xxx$/, // may apply this only for some modules
         options: {
           postcss: ...
         }
       })
     ]

npm ERR! Darwin 12.6.0
npm ERR! argv "/usr/local/bin/node" "/Users/dmitrizaitsev/.npm-global/bin/npm" "run" "build"
npm ERR! node v6.9.2
npm ERR! npm  v4.0.5
npm ERR! code ELIFECYCLE
npm ERR! [email protected] build: `webpack`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] build script 'webpack'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the webpack2-blocks-test package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     webpack
npm ERR! You can get information on how to open an issue for this project with:
npm ERR!     npm bugs webpack2-blocks-test
npm ERR! Or if that isn't available, you can get their info via:
npm ERR!     npm owner ls webpack2-blocks-test
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     /Users/dmitrizaitsev/Dropbox/Sandbox/webpack2-blocks-test/npm-debug.log

Here is the repo to reproduce the errors:

https://github.com/dmitriz/webpack-blocks-wp2-test

Test App not working

I get the following error when trying to run the test app, eventhough i've ran yarn, and npm install both.

sh: webpack-dev-server: command not found

@webpack-blocks/sass Allow using indentedSyntax

Problem
When I want to write .sass files instead of .scss, there should be a way to pass query params to the sass loader like sass?indentedSyntax, right?

Any thoughts how to make this configurable?

Add a nice way to define constants

It would be great to have at the core level of webpack-blocks a way to define constants within the code. Right now, we could do that using the DefinePlugin but I think it deserves a nicer way.

Here is my proposal:

const { createConfig, defineConstant } = require('@webpack-blocks/webpack')

module.exports = createConfig([
  defineConstant('process.env.NODE_ENV', process.env.NODE_ENV),
  defineConstant('__API__URL', process.env.API_URL),
  // ...
])

And it would be transformed by:

new webpack.DefinePlugin({
  'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
  '__API_URL__', JSON.stringify(process.env.API_URL)
})

We might want to stack them instead of doing it with a single plugin. I don't know if it will be possible the way things are built with webpack-blocks.

Or maybe it could be a defineConstants that takes more than a single one.

What do you think? I can make a PR if you want to experiment with it.

Proper preset support

In fact webpack-blocks already makes it quite easy to group blocks. But it would be more convenient if @webpack-blocks/core would export another function that works like env(), but without checking the environment.

How it could look like

const { group } = require('@webpack-blocks/core')
const babel = require('@webpack-blocks/babel6')
const postcss = require('@webpack-blocks/postcss')

const defaultPostcssPlugins = [ /**/ ]

module.exports = function myPreset ({ addPostcssPlugins }) {
  const postcssPlugins = defaultPostcssPlugins.concat(addPostcssPlugins || [])

  return group([
    babel(),
    postcss(postcssPlugins)
  ])
}

How it could be used

// webpack.config.js
const { createConfig, entryPoint, setOutput } = require('@webpack-blocks/webpack')
const myPreset = require('my-preset')

module.exports = createConfig([
  myPreset(),
  entryPoint('./src/app'),
  setOutput('./build/bundle.js')
])

Unexpected result of entry points merge

I have multiple entry points in my webpack config:

  entryPoint({
    'a': './a.js',
    'b': './b.js',
  }),

I have also defined development env with devServer block:

  env('development', [
    devServer({ stats: 'minimal' }),
    setOutput({
      filename: '[name].js',
      publicPath: "http://localhost:8080/javascripts/",
    }),
  ]),

This devServer block returns 'webpack/hot/only-dev-server' for each entry point key, letting webpack-merge merge it later with original entry points:
https://github.com/andywer/webpack-blocks/blob/master/packages/webpack-common/src/devServer.js#L43-L59

In the end one would expect to get following entry points in development env:

      { a: [ './a.js', 'webpack/hot/only-dev-server' ],
        b: [ './b.js', 'webpack/hot/only-dev-server' ] }

What I'm observing however is:

      { a: [ './a.js', 'webpack/hot/only-dev-server' ],
        b: [ './a.js', 'webpack/hot/only-dev-server' ] }

First entry point value is replicated over latter entry keys.

I've managed to isolate minimal configuration under which this behaviour can be reproduced. Have a look at: https://github.com/pawelpacana/webpack-blocks-multiple-entries-dev-server-merge

For clarity, precise software versions under which I can observe this behaviour:

$ yarn --version
0.18.1

$ node -v
v7.4.0

$ grep webpack-blocks package.json
    "@webpack-blocks/babel6": "^0.3.0",
    "@webpack-blocks/dev-server": "^0.3.0",
    "@webpack-blocks/extract-text": "^0.3.0",
    "@webpack-blocks/postcss": "^0.3.0",
    "@webpack-blocks/sass": "^0.3.0",
    "@webpack-blocks/webpack": "^0.3.0",

As a workaround I've used following snippet to get predictable merge behaviour:

   env('development', [
-    devServer({ stats: 'minimal' }),
+    customConfig({
+      entry: {
+        'a': ['webpack/hot/only-dev-server'],
+        'b': ['webpack/hot/only-dev-server'],
+      },
+      devServer: {
+        stats: 'minimal',
+        hot: true,
+        inline: true,
+        historyApiFallback: true
+      }
+    }),
    setOutput({
      filename: '[name].js',
      publicPath: "http://localhost:8080/javascripts/",
    }),
  ]),

postcss webpack block

Hiya,
I'm wondering here, the sass webpack block index.js defines the following:
loaders: [ 'style-loader', 'css-loader', 'sass-loader' ]
And the postcss webpack block is so:
loaders: [ 'postcss-loader' ]
But the postcss-loader specifies that you need style-loader and css-loader.
So my question is, how can I add a separate loader without using the "blocks" approach to make this work?

Only using the post-css webpack block I get the following error:

var content = require("!!./../node_modules/css-loader/index.js!./App.css");
ERROR > if(typeof content === 'string') content = [[module.id, content, '']];

Which I think is because I don't have the style nor css loader installed.

Thanks in advance!

Non-builder solutions

I like your project. Honestly, I thought about something like it. Modern webdev is so hard to configurate, and you solve some problems.

But what do you think if we could solve more problem in one project:

  • Run tests
  • Run lint

Imagine if in future you could write webpack-blocks test and it will run tests in best practices.

Something like create-react-app, but modular in your way.

So, my question in short form: what do you think about handling other non-builder webdev processes like tests, linters, etc?

Document how to deal with new MIME types

There are two ways to handle this:

  1. Just add them to the default types. Easy, but requires a new @webpack-blocks/core release and won't work with any previous @webpack-blocks/core version.
  2. Have a pre hook that does context.fileTypes.add(). No new release of @webpack-block/core necessary.
  3. (both: 2., but still add it to the default types like 1.)

Not completely sorted out yet

  • What is the suggested way of doing that (see options above)?

To Do

  • Improve documentation ("How to write a block")

Idea: webpack config CLI

Just a quick thought:
A webpack config command line tool to set up and administrate a webpack config might be nice.

# Set up basic webpack configuration
$ webpack-blocks init
Installing dependencies...
Creating webpack.config.js...
Adding scripts to package.json...

# List used features
$ webpack-blocks installed
Features in use:
  Babel
  PostCSS

Development features:
  Dev Server
  Source Maps

Production features:
  Extract Text Plugin

# Add feature
$ webpack-blocks add [--dev|--prod] sass
Installing dependencies...
Adding to webpack config...

# Show documentation
$ webpack-blocks help sass
This is the sass block providing SASS/SCSS support for webpack. Uses node-sass via sass-loader.
Documentation: https://www.npmjs.com/package/@webpack-blocks/sass

Easier setup

Current situation

webpack-blocks makes writing easy-to-maintain webpack configurations simpler. But it is still not trivial for a newbie to set up a webpack config in the first place.

You have to install multiple webpack-block packages and still need to be aware of which blocks you need and what the best practices are (like using DefinePlugin to set process.env to production when using React).

Ideas to improve things

  • Bundle most common webpack blocks together in one npm package (like Babel, Dev server, PostCSS)
  • Provide best practice settings & plugins out of the box easily (like @webpack-blocks/react-preset)
  • CLI tool to install packages and set up package.json scripts (loosely based on #1)

Additional considerations:

  • Potential CLI tool could allow different source code templates to be used (React vs Angular 2, Redux vs Mobx vs RxJs, CSS vs Styled components)

Add simple testing to test-app

I fear we will always have issues with the test-app unless there is some basic testing, even though the test app is no production code.

Add dependencies / devDependencies on blocks

It would be great if it was possible to automatically install the dependencies / devDependencies needed when using a block.

That way, you don't need to know when using @webpack-block/typescript which typescript loader you need to use with it.

Is there a way to achieve something like that ATM?

Discussion: Support for DLL

DLL plugins helps webpack not to loop through dependencies when webpack rebuild itself. Are you guys supporting this features?

Idea: add block config to loaders

So first off I want to say this is an amazing concept. It strips away the complexity of having to setup an entire webpack config.

I had an idea pop into my head and I wanted to run it by you to run it by you.

Currently you are supporting loaders on a case to case basis in your packages folder. My thought was maybe you could add a configuration folder to each loader at the root level. This package folder would signify it supports webpack blocks, for instance a .block folder with the index that contains the configuration for that module in a certain form whether it be json, js, etc.

One downside I see is that not all repo's would partake (although I do not see why not). If however they chose not too, you could still support them in a wrapper within this repo.

A major bonus I see here is that block folder would then be updated with the repo of the loader, so it would follow the semantic/configuration changes of that loader. This would mean that the webpack ecosystem as is would remain the same. People install loaders, loaders contain blocks, webpack blocks bootstraps those blocks.

Webpack block would then read the configuration of the block in the main repo, the block would be more of generic builder function.

import {createConfig, compose} from 'webpack-blocks';
const wpDevServer = require('webpack-dev-server/block');
 // creates a builder function based off the config
const blocks = compose(wpDevServer(/*config*/), ...);

export createConfig(...blocks);

I am of course open to feedback and possible drawbacks.

Sincerely,
Mo Binni

Add block for OfflinePlugin (PWAs πŸŽ‰)

Seems like a good idea to add a block for the OfflinePlugin.

Might use the OfflinePlugin's defaults or use the options set by react-boilerplate if no custom options are provided (don't forget to credit/add link to react-boilerplate if using its default options).

Purpose: The OfflinePlugin makes it easy to integrate a standard service worker to turn your webapp into an offline-ready progressive webapp (PWA).

Webpack 2 support

Webpack 2 shall be supported!

Backed by public interest.

To Do:

  • Create new webpack blocks: webpack2, dev-server2, extract-text2
  • Update test app
  • Make webpack and webpack2 blocks DRY

Overriding default config for file-loader and url-loader

I have a question. This configuration for my .less files

module.exports = createConfig([
setContext(stylesDirectory),
entryPoint({
    "style-day-mode": "style-day-mode",
    "style-night-mode": "style-night-mode"
}),
setOutput({
    path: helpers.root("./wwwroot/styles"),
    filename: "[name].js"
}),
addPlugins([
    new webpack.NoErrorsPlugin(),
    new webpack.optimize.OccurenceOrderPlugin(true),
    new ExtractTextPlugin("[name].css", {allChunks: true})
]),
customConfig({
    resolve: {
        extensions: ["", ".less"],
        modulesDirectories: ["node_modules", stylesDirectory]
    },
    module: {
        loaders: [
            {
                test: /\.less$/,
                loader: ExtractTextPlugin.extract("css!less")
            },
            {
                test: /\.(eot|svg|ttf|woff|woff2)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
                include: /node_modules/,
                loader: "file-loader?name=../fonts/[name].[ext]"
            },
            {
                test: /\.(gif|png)$/,
                include: /ReportWriter/,
                loader: "url-loader?name=../images/[name].[ext]&limit=10240"
            }
        ]
    },
})
]);

however it's conflicting with default @webpack-blocks config created in createBaseConfig.
Is there any way to override the behavior?

defineConstants is evaluated build-time and may lead to bugs on different environment

Imagine you deploy your application on different targets, eg amazon, local, remote server, etc. You pass some links environment vars with service addresses. You expect to have binding. Instead you have webpack replace all process.env notation with constant value - not reference.
This way defineConstants is capable only for providing environment constants of machine the bundle was built on. Having this bundle deployed on different environment makes no sense, as all constants are not reevaluated and lead to breakage of app.
I do suggest to add comment on this somewhere in docs as it may lead to confusion.

Generating stats.json

It would be great to add an option to generate the stats.json file out of the box.

I use this on most of my project. Maybe this would be easy to plug.

This is an example of a plugin I use to do it:

const chunks = ['assetsByChunkName', 'publicPath'];

function generateWebpackStats() {
  this.plugin('done', stats => {
    const webpackStats = stats.toJson({ chunks: true });

    // Only keep what we need for the server
    for (var key in webpackStats) {
      if (chunks.indexOf(key) < 0) {
        delete webpackStats[key];
      }
    }

    fs.writeFileSync(file, JSON.stringify(webpackStats, null, 4));
  });
}

Idea: Configuration file wizard webapp

Build a simple webapp for creating webpack configs.

Input:

  • Entry point(s)
  • Output file path(s)
  • Features like babel, dev-server/dashboard, postcss, css modules, sass, ... (select babel, dev-server and autoprefixer by default)

Output:

  • Webpack config file (+ download button)

Show next steps:

  • start and build scripts to add to package.json
  • How to run the dev server / how to trigger a production build

Support for happypack

happypack allows webpack to be parallelized across threads. Adding support for it and webpack dll's would be a huge leap in terms of build speeds.

Willing to make a PR for this with the help of @amireh

Thoughts?

Example of using sass ?

Hi,
I tried to use sass, imported .scss files but it gives some build errors (loader is needed for this format, etc.).
Do you have an example for using sass?
Thanks.

Desktop application to configure webpack-blocks

While writing a configuration with code is by far the most flexible way of doing it, it would be great to be able to use a desktop application to make things more easy and clear to use.

We talked before about a CLI tool, but I think the UI would be too complex just for the console.

With webpack-blocks, the concept of blocks is very present and it would be cool to make that more visual. You could configure each block, drag&drop them in the order you want them, group or split them when using env and group blocks and load/save your webpack.config.js file.

I think it should let people do what they want within the code and at the same time give an easy way to edit it within the application.

I know this is not a simple challenge but I would like to explore it from a user perspective first.

To build the application, we could use Electron so that it is cross-platform and powered by the beautiful Web behind :)

I'll try to draw a mockup this week to expose more the idea and from there let me know what you think!

I'll start something in a different repo as a starting point but I feel like Andy and the other contributors might have great ideas about that too.

Defining multiple entry points

I wish to divide my JS codes into mulltiple bundles, by specifying multiple entry points and output file names. I'd also like to know how to define aliases while including node/bower modules and libraries.

Is there a way to do it using webpack-blocks?

Example webpack.config.js file

Add webpack version to context

The context should contain the webpack version so blocks that need to configure loaders/plugins differently for webpack 1 and webpack 2 can rely on that version.

The postcss block does this kind of differentiation already, but in a quite hacky way. And it seems that the tslint block will need to do something similar (see #92).

Create preset for common basics: Babel + Autoprefixer + best practice config

Since probably 90%+ of the users will want to have Babel and the autoprefixer it would be nice to ship a preset (using group()) that sets some blocks configured in a best-practice manner:

  • Babel with babel-preset-env (target last 2 versions for instance)
  • PostCSS with autoprefixer (similar target as set for babel-preset-env)
  • Set process.env.NODE_ENV (in output code, using defineConstants)
  • Source maps in development mode
  • Minification and optimization in production build mode
  • Set resolve.extensions to webpack defaults plus the popular '' (so it's nice to use with createConfig.vanilla() as well; only needed for webpack 1.x)

Not sure if those should be included

  • HTML loader
  • HtmlWebpackPlugin

Problems left to solve

  • Cannot set PostCSS plugins from within webpack config anymore when using webpack 2 (fixed by #74 πŸŽ‰)

Context seems to have changed for @webpack-blocks/dev-server2

Using webpack2 and webpack-dev-server2. Having a build time error while using webpack-devserver-2 block.

See this gist for a minimal reproducible example.
You can also clone this repo, npm install, npm start

Error here:

/Users/.../example-webpack/node_modules/@webpack-blocks/webpack-common/lib/devServer.js:58
    plugins: [new context.webpack.HotModuleReplacementPlugin()]
                                 ^
TypeError: Cannot read property 'HotModuleReplacementPlugin' of undefined
    at postConfig (/Users/fraleyj/example-webpack/node_modules/@webpack-blocks/webpack-common/lib/devServer.js:58:34)
    at /Users/fraleyj/example-webpack/node_modules/@webpack-blocks/core/lib/index.js:116:25
    at Array.reduce (native)
    at invokeConfigSetters (/Users/fraleyj/example-webpack/node_modules/@webpack-blocks/core/lib/index.js:115:24)
    at invokePostHooks (/Users/fraleyj/example-webpack/node_modules/@webpack-blocks/core/lib/index.js:130:10)
    at Object.createConfig (/Users/fraleyj/example-webpack/node_modules/@webpack-blocks/core/lib/index.js:40:29)
    at createConfig (/Users/fraleyj/example-webpack/node_modules/@webpack-blocks/webpack2/index.js:58:15)
    at Object.<anonymous> (/Users/fraleyj/example-webpack/webpack.config.js:9:18)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)

I don't understand why, but it looks like this use of context is mixed up somehow:

function postConfig (context, config) {
  const entryPointsToAdd = context.devServer.entry.length > 0
    ? context.devServer.entry
    : [ 'webpack/hot/only-dev-server' ]
  // console.log(context) <---- this has HotModuleReplacementPlugin on it, does not have webpack.HotModuleReplacementPlugin
  return {
    devServer: Object.assign({
      hot: true,
      historyApiFallback: true,
      inline: true
    }, context.devServer.options),
    entry: addDevEntryToAll(config.entry || {}, entryPointsToAdd),
    plugins: [
      new context.webpack.HotModuleReplacementPlugin() // <--- context.webpack === undefined
    ]
  }
}

The issue seems to be introduced by this PR.

I can open a PR with the fix, but I don't understand the assumptions here or how context is intended to work, such that the above PR might've been confused.

Add testing/setup documentation for contributors

Package linking / testing before publishing

  • lerna bootstrap
  • Point out that lerna bootstrap is run automatically on postinstall (on Travis CI, too)
  • npm link

Testing concept

Types of tests:

  • Unit tests
  • Integration tests
  • End-to-end tests

(What they reside, where they occur and when to write which one(s))

Common pitfalls

  • e2e tests: Copy dependencies of blocks to test into the devDependencies of webpack/webpack2

Question: why use Object.assign rather than just setting hook properties on the fn?

In reading the docs for block creation, I was wondering if there was a reason why you use Object.assign rather than just setting the properties on the function directly?

I'm not trying to nitpick here, only trying to make sure I'm not missing something since it seems that the result would be the same.

So the existing docs give this example using Object.assign:

function myBlock () {
  const blockFunction = (context, config) => ({ /* webpack config snippet */ })

  return Object.assign(blockFunction, {
    pre: preHook,
    post: postHook
  })
}

function preHook (context) {
  // Manipulate the `context` here (register a new file type, for example)
}

function postHook (context, config) {
  return { /* webpack config snippet */ }
}

And it seems to me that the equivalent code is simply to set the properties on the function directly.

function myBlock () {
  const blockFunction = (context, config) => ({ /* webpack config snippet */ })
  blockFunction.pre = preHook;
  blockFunction.post = postHook;
  return blockFunction;
}

function preHook (context) {
  // Manipulate the `context` here (register a new file type, for example)
}

function postHook (context, config) {
  return { /* webpack config snippet */ }
}

Is there any technical reason that you are recommending using Object.assign or would it be just the same to set the properties directly?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.