All Projects → easy-webpack → Core

easy-webpack / Core

Licence: mit
An easy way to create configuration files for Webpack

Programming Languages

typescript
32286 projects

Labels

Projects that are alternatives of or similar to Core

React Universal Boiler
A bold way to begin your next great universal React application. Uses Webpack 3, React 16, Redux, and more for a great developer experience.
Stars: ✭ 65 (-5.8%)
Mutual labels:  webpack
Import Http
Import modules from URL instead of local node_modules
Stars: ✭ 1,150 (+1566.67%)
Mutual labels:  webpack
Flask React Boilerplate
Simple boilerplate for a Flask backend and React client
Stars: ✭ 69 (+0%)
Mutual labels:  webpack
Bathe
The simplest WordPress starter theme including full setup for Sass, PostCSS, Autoprefixer, stylelint, Webpack, Eslint, imagemin, Browsersync, etc.
Stars: ✭ 65 (-5.8%)
Mutual labels:  webpack
React Seed
UruIT's react seed project
Stars: ✭ 67 (-2.9%)
Mutual labels:  webpack
Cordovue
A sample Apache Cordova application using VueJS.
Stars: ✭ 66 (-4.35%)
Mutual labels:  webpack
Vue
Stars: ✭ 65 (-5.8%)
Mutual labels:  webpack
Sketch Loader
Webpack loader for Sketch (+43) files
Stars: ✭ 69 (+0%)
Mutual labels:  webpack
Vue Web Extension
🛠️ A Vue CLI 3+ preset (previously a Vue CLI 2 boilerplate) for quickly starting a web extension with Vue, Babel, ESLint and more!
Stars: ✭ 1,147 (+1562.32%)
Mutual labels:  webpack
Eleventy Webpack
A barebone Eleventy and Webpack boilerplate 🎈
Stars: ✭ 68 (-1.45%)
Mutual labels:  webpack
Vscode Ts Webpack Node Debug Example
VSCode TypeScript Webpack Node Debug Example
Stars: ✭ 66 (-4.35%)
Mutual labels:  webpack
Extracted Loader
It reloads extracted stylesheets extracted with ExtractTextPlugin
Stars: ✭ 67 (-2.9%)
Mutual labels:  webpack
App Template
Boilerplate for Angular apps
Stars: ✭ 67 (-2.9%)
Mutual labels:  webpack
Starter React Flux
Generate your React PWA project with TypeScript or JavaScript
Stars: ✭ 65 (-5.8%)
Mutual labels:  webpack
Spring Vue Sample
Stars: ✭ 69 (+0%)
Mutual labels:  webpack
Html5 Boilerplate
A simple, fast, modern, pure html, css (and sass), js, live reload starter template
Stars: ✭ 65 (-5.8%)
Mutual labels:  webpack
Ifme
Free, open source mental health communication web app to share experiences with loved ones
Stars: ✭ 1,147 (+1562.32%)
Mutual labels:  webpack
Node Blog
🔥✨ A react blog project base on nodejs, nestjs, mongoose, typescript, react, ant-design,nextjs
Stars: ✭ 69 (+0%)
Mutual labels:  webpack
Django Webpacker
A django compressor tool that bundles css, js files to a single css, js file with webpack and updates your html files with respective css, js file path.
Stars: ✭ 69 (+0%)
Mutual labels:  webpack
Jolly
Production ready boilerplate for hapi.js
Stars: ✭ 68 (-1.45%)
Mutual labels:  webpack

Easy Webpack

Creating and maintaining configuration files for Webpack can be both intimidating and a real chore, especially for people who don't want to invest hours or even days to studying the far-from-great-but-slowly-getting-better docs, testing and debugging various options, when in reality, they only wanted to get on with their real work: developing apps, sites or libraries.

Easy Webpack presents solutions to this problem to a variety of users in different ways:

  • to those that simply "want things to work out of the box", by easily stacking together pre-made preset configs to achieve the desired effect
  • to more advanced users, by exposing useful helper methods that make it possible to separate concerns and make parts of the config easily extendable or conditional (e.g. based on NODE_ENV).

Instead of defining the Webpack configuration file as a flat, "black box" that contains all the features mixed up together in a long file of strings, objects, plugin imports and arrays, it makes it possible to modularize and clean-up the config by clearly separating individual features - as stackable configuration blocks, which in turn increase readability, reusability and ease-of-maintainance.

Usage

To install the core functionality of easy-webpack run the following command:

npm install @easy-webpack/core --save-dev

Note: You'll also need to have webpack installed.

Now, you can use the Easy Webpack's core function, generateConfig in your webpack.config.js file.

const generateConfig = require('@easy-webpack/core').generateConfig;

Generating Configs

generateConfig is a helper method that can be used to generate a desired config file from different "configuration parts" or "presets" that are passed into it as arguments. The arguments can either be simple Objects or a Function, that returns the desired configuration Object, or a mixture of both. The order of arguments matters.

It is possible to run generateConfig many times consecutively, by using the output of the previous execution as the first argument of the next one. This might be useful in situations where you'd like to add a set of features conditionally.

Depending on your current knowledge of Webpack, please either read on or jump ahead:

  • I know very little about Webpack, I'd just like to use it, please. Jump here.
  • I have already created configuration files for Webpack in the past and I'd like to know how Easy Webpack can help simplify my workflow. Awesome! Read on.

How it works

By default, when passing an Object, the generateConfig function does the following:

  • recursively merge nested objects (so that new configuration fields can be added, rather than overwritten by successive configs)
  • non-recursively append Arrays (so you can add plugins on top of existing ones, rather than replace all the previously defined ones)
  • override strings, booleans, numbers and other types -- in case they were defined in one of the previous configs

When passing an Object generating Function, the effects are similar, with one exception:

  • Arrays are always literally replaced

To get an intuitive feel of what it does in its most basic form, take a look at the following code:

const a = { a: { text: 'abc', array: [ 1, 2, 3 ] } };
const b = { a: { text: 'xyz', array: [ 4, 5, 6 ] }, b: 'something else' };

const merged = generateConfig(a, b);

// 'merged' is now a combination of both 'a' and 'b', 
// with the exception of 'a.text' which was replaced with the value from 'b'
// { a: { text: 'xyz', array: [ 1, 2, 3, 4, 5, 6 ] }, b: 'something else' };

Example with pure Objects

To illustrate how Easy Webpack works, let's create a simple Webpack configuration file using its highlight feature - generateConfig.

First, let's define some configuration objects, each clearly representing separate concerns we'd like to address in the output config file:

Click here to expand the example
const path = require('path');
const DefinePlugin = require('webpack/lib/DefinePlugin');

const common = {
  entry: {
    'app': ['./src/main']
  },
  output: {
    path: path.resolve('dist'),
  }
}

const development = {
  devtool: 'cheap-module-inline-source-map',
  debug: true,
  output: {
    filename: '[name].bundle.js',
    sourceMapFilename: '[name].bundle.map',
    chunkFilename: '[id].chunk.js'
  },
  plugins: [
    new DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify('development')
      }
    })
  ]
}

const production = {
  devtool: 'source-map',
  debug: false,
  
  output: {
    filename: '[name].[chunkhash].bundle.js',
    sourceMapFilename: '[name].[chunkhash].bundle.map',
    chunkFilename: '[id].[chunkhash].chunk.js'
  },
  
  plugins: [
    new DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify('production')
      }
    })
  ]
}

const css = {
  module: {
    loaders: [{
      test: /\.css$/i,
      loaders: ['style', 'css']
    }]
  }
}

We can now use the generateConfig function from @easy-webpack/core to combine those parts into one, functional configuration object, which differs depending on the NODE_ENV:

const generateConfig = require('@easy-webpack/core').generateConfig;

let config;

switch (process.env.NODE_ENV) {
  case 'development':
    config = generateConfig(common, development, css);
    break;
  case 'production':
    config = generateConfig(common, production, css);
    break;
}

module.exports = config;

This offers you a clear separation of concern in terms of defining your configuration files.

Advanced usage

Literal Replace

You can achieve literal manipulations by using literalReplace:

const literalReplace = require('@easy-webpack/core').literalReplace;

const initial = {
  plugins: [ new SomeWebpackPlugin() ]
}

const override = {
  plugins: literalReplace( [ AnotherWebpackPlugin() ] )
}

const config = generateConfig(initial, override);
// the output config will only have 'AnotherWebpackPlugin()', but not SomeWebpackPlugin, because of literalReplace
Object Generators

If you need more powerful and fine grained control over the blocks of your configuration (like prepending arrays or re-using current state), instead of passing in the object, you may also pass in a function, that generates the desired configuration part.

The function you pass in will be evaluated with its this bound to the current configuration state, which means you can access previous values in order to modify or extend them. This makes it possible to do virtually any transformation to the config in a consistent manner, e.g. use values previously defined to compute the desired outcome.

By further creating wrapper functions that generate functions that generate configuration objects (that's a mouthful!), you can create very clean wrappers for specific functionality (this is also how our preset configs are made):

Click here to expand the example
import {get} from 'lodash'; // helper for extracting current value //

function css({ filename = '[name].css', allChunks = false, sourceMap = false, extractText = undefined, resolveRelativeUrl = undefined } = {}) {
  return function css() {
    const loaders = ['style', `css${sourceMap ? '?sourceMap' : ''}`];

    if (resolveRelativeUrl) {
      loaders.push(`resolve-url${sourceMap ? '?sourceMap' : ''}`);
      sourceMap = true; // source maps need to always be on for this
    }

    const extractCss = extractText === false;
    const providedInstance = extractText instanceof ExtractTextPlugin;

    if (!providedInstance)
      extractText = extractCss ? new ExtractTextPlugin(filename, extractText instanceof Object ? extractText : { allChunks, sourceMap }) : null;

    const config = {
      module: {
        loaders: get(this, 'module.loaders', []).concat([{
          test: /\.css$/i,
          loaders: extractCss ? extractText.extract(...loaders.slice(1)) : loaders
        }])
      }
    }

    if (extractText && !providedInstance) {
      config.plugins = [
        extractText
      ].concat(get(this, 'plugins', []))
    }

    if (resolveRelativeUrl instanceof Object) {
      config['resolveUrlLoader'] = resolveRelativeUrl
    }

    return config
  }
}

Note that for simple uses, such as overriding a setting, or adding a plugin, using a simple object is usually enough.

The Easy Webpack Ecosystem - Feature and Configuration Presets

Easy Webpack offers a number of pre-made feature preset NPM packages that can be used to quickly add desired functionality to your Easy Webpack config file. Each feature comes with its own set of dependencies, so that you - the user - do not have to research changes, or worry about the best possible implementation of a given feature at a given time. The idea is as simple as it gets: you install the module, stick it into your config and it should just work.

This is great in a number of scenarios, such as:

  • you're starting out a project and don't want to think too hard about how to configure Webpack
  • you want to delegate the task of implementing the configuration of certain Webpack features to other people
  • you don't neccessairly feel like researching ze internets every other month for an updated tutorial for the up-to-date best practices for implementing a given feature, you'd rather npm update and be done with it
  • you want a clean "base" config that works, that you can override/append with your own custom features or parts

If you see value in any of the above mentioned scenarios, you should give feature-config presets a try.

Using Feature Configuration Presets

You can see all the published feature configs on NPM. You'll find a range of packages, from opionionated Production and Development presets, through Babel, TypeScript, CSS, LESS and SASS support, to platform-specific support such as Aurelia or Electron.

As a rule, all the official Easy Webpack packages are made more robust by returning functions that generate Objects, meaning, the packages can expose a number of parameters to the end-user, which can be used for customization of a given feature (example below).

Every Easy Webpack package includes typings, which means IDEs such as Visual Studio, Visual Studio Code or Webstorm will show appropriate autocomplete listing all the possibile options. Since the feature configs are still mostly undocumented (Pull Requests appreciated!), its best to rely on the typings and refer to the source code as a last resort.

To use a given preset simply:

  1. install it via NPM as you normally would any package

    npm install @easy-webpack/config-css --save-dev
    
  2. insert a call to it as an argument to your generateConfig call (shown in the example below)

An example webpack.config.js that uses strictly configuration presets might then look like this:

const baseConfig = { ... }; // project-specific config like the entry file(s)

module.exports = generateConfig(
  baseConfig,

  require('@easy-webpack/config-env-production')
    ({ compress: true }),
    
  require('@easy-webpack/config-aurelia')
    ({ title: 'My Awesome Website' }),

  require('@easy-webpack/config-typescript')(),
  require('@easy-webpack/config-html')(),

  require('@easy-webpack/config-css')
    ({ filename: 'styles.css', allChunks: true, sourceMap: false }),

  require('@easy-webpack/config-fonts-and-images')(),
  require('@easy-webpack/config-global-bluebird')(),
  require('@easy-webpack/config-global-jquery')(),
  require('@easy-webpack/config-global-regenerator')(),
  require('@easy-webpack/config-generate-index-html')
    ({ minify: true }),

  require('@easy-webpack/config-uglify')
    ({ debug: false }),
    
  // 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
);

You may naturally replace, override or append any custom config by simply placing the desired config Object or Object-generating Function into the arguments passed into generateConfig like shown in the comments above.

For a fully-featured example, take a look at Aurelia's Navigation Skeleton.

Why delegate parts of my config file to ze internets, why a gazillion NPM modules, one per each simple feature?

The benefit of having parts of the config in separate NPM modules is that the community can fix bugs and optimize the config file without you - the developers - having to do anything else than npm update. No need for blog posts with tedious migrations to new settings -- the deal is: just update the package.

To the ney-sayers out there, my response is: When somebody wants their own, unmanaged settings, they probably know what and why they're doing something. One can always copy & paste the config out from the managed package or write their own from scratch. Ultimately, it's like the difference between managed and unmanaged webhosting -- you should always choose the right tool for the job.

Notes on usage in production

If you're running a production-grade product that's using NPM packages, it is considered good practice to either lock your dependencies to a patch level, or use shrinkwrap to deep-lock them altogether and upgrade with the help of tests to confirm your code works in the updated scenario. If you just "upgrade the hell out of it" for the sake of upgrading, then I can't be blamed if things break.

Every config package follows SemVer, i.e. no breaking changes will be made to config files without bumping a major version. Minor bumps and bug fixes will only include: code maintenance, upgrade tasks, switches for better defaults (e.g. a better compression algorithm, a more compatible default devtool - things of that sort).

Note that it is ultimately the developers responsibility to ensure he has set correct SemVer range for the packages, just like it is the mainainers responsitility to follow SemVer in a SemVer environment.

What are others saying

Great job!! Something to 🤔: Make #webpack more usable vs. abstract it's complexity with another tool? What you've made is still 👌💯

-- Sean T. Larkin | @TheLarkInn | Webpack Core Team | Source: Twitter Status

You have done a fantastic job by creating easy-webpack. Thank you so much. You don't know how frustrated I was learning Webpack and creating a working webpack.config.js

-- @rajajhansi | Source: GitHub Issue

Webpack has quite a steep learning curve when you start getting knee-deep into it. That new Easy Webpack stuff is simply beautiful -- seriously it's so good. Lots of configurations for Webpack projects without needing to pull your hair out.

-- @Vheissu | Source: Gitter @ June 28, 2016 8:39 AM

easy webpack [is] a great idea

-- @rquast | Source: Gitter @ June 28, 2016 8:42 AM

Contributing

We use Semantic Release, which means:

  • version is set during release, in the CI, not in Git's copy of package.json
  • commits should conform to the AngularJS Commit Message Convention, i.e. these rules

If you created an Easy Webpack feature configuration preset package please add the conventional easy-webpack tag, so that others may easily find it. In case you would like to migrate it under the @easy-webpack scope, open an issue here and we'll see what we can do! It would be best if you used one of the pre-existing packages as a template (Semantic Release + AVA + TypeScript).

Prior art and alternatives

Direct inspiration for this project:

Check out alternatives projects that I was not aware of when developing Easy Webpack:

Hall of Fame

Made possible thanks to these brave souls:

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].