' }
61 | })
62 | )
63 | })
64 | }
65 |
66 | return rule
67 | })
68 | })
69 | const output = Object.assign({}, originalConfig.output, {
70 | path: path.basename(originalConfig.output.path)
71 | })
72 | const config = Object.assign({}, originalConfig, {
73 | plugins: originalConfig.plugins.map(p => p.constructor.name),
74 | module,
75 | output
76 | })
77 | t.snapshot(config)
78 |
79 | process.env.NODE_ENV = NODE_ENV
80 | })
81 |
82 | test('it builds', async t => {
83 | const buildLocation = path.resolve(__dirname, '../build')
84 | rimraf(buildLocation, () => {})
85 | await execa('yarn', ['build'], { cwd: path.resolve(__dirname, '..') })
86 |
87 | testHtml()
88 | testCss()
89 | testJs()
90 |
91 | function testHtml() {
92 | const html = fs.readFileSync(path.resolve(buildLocation, 'index.html'), { encoding: 'utf8' })
93 | const re = //
94 |
95 | t.true(re.test(html))
96 | t.true(html.includes(''))
97 | }
98 |
99 | function testJs() {
100 | const js = fs.readFileSync(path.resolve(buildLocation, 'bundle.js'), { encoding: 'utf8' })
101 | t.true(js.includes('No content here. We only test the build process 😉'))
102 | }
103 |
104 | function testCss() {
105 | const files = fs.readdirSync(path.resolve(buildLocation, 'css'), { encoding: 'utf8' })
106 | t.is(files.length, 1)
107 |
108 | const css = fs.readFileSync(path.resolve(buildLocation, 'css', files[0]), { encoding: 'utf8' })
109 | t.true(css.startsWith('.'))
110 | t.true(css.endsWith('{margin:30px auto;text-align:center}'))
111 | }
112 | })
113 |
114 | function requireConfig() {
115 | if (require.cache[configFile]) {
116 | delete require.cache[configFile]
117 | }
118 | return require(configFile)
119 | }
120 |
--------------------------------------------------------------------------------
/packages/sample-app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Demo
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/packages/sample-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sample-app",
3 | "private": true,
4 | "version": "2.1.0",
5 | "scripts": {
6 | "build": "cross-env NODE_ENV=production webpack --config webpack.config.babel.js",
7 | "start": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.babel.js"
8 | },
9 | "engines": {
10 | "node": ">= 6.0"
11 | },
12 | "devDependencies": {
13 | "@babel/core": "^7.1.2",
14 | "@babel/preset-env": "^7.1.0",
15 | "@babel/preset-react": "^7.0.0",
16 | "@types/node": "^10.11.6",
17 | "@types/react": "^16.4.16",
18 | "cross-env": "^5.2.0",
19 | "cssnano": "^4.1.4",
20 | "eslint-plugin-react": "^7.11.1",
21 | "execa": "^1.0.0",
22 | "html-webpack-plugin": "^3.2.0",
23 | "react": "^15.6.2",
24 | "react-dom": "^15.6.2",
25 | "react-hot-loader": "^3.1.3",
26 | "rimraf": "^2.6.2",
27 | "typescript": "^3.1.2",
28 | "webpack": "^4.20.2",
29 | "webpack-blocks": "^2.1.0",
30 | "webpack-cli": "^3.1.2",
31 | "webpack-dev-server": "^3.1.9"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/packages/sample-app/src/App.css:
--------------------------------------------------------------------------------
1 | .app {
2 | margin: 30px auto;
3 | text-align: center;
4 | }
5 |
--------------------------------------------------------------------------------
/packages/sample-app/src/App.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 | const styles = require('./App.css')
3 |
4 | const App: (() => JSX.Element) = () => (
5 | No content here. We only test the build process 😉
6 | )
7 |
8 | export default App
9 |
--------------------------------------------------------------------------------
/packages/sample-app/src/index.dev.js:
--------------------------------------------------------------------------------
1 | import 'react-hot-loader/patch'
2 |
3 | import React from 'react'
4 | import ReactDOM from 'react-dom'
5 | import { AppContainer } from 'react-hot-loader'
6 | import App from './App'
7 |
8 | const mountPoint = document.getElementById('root')
9 | ReactDOM.render(
10 |
11 |
12 | ,
13 | mountPoint
14 | )
15 |
16 | if (module.hot) {
17 | module.hot.accept('./App', () => {
18 | const NewApp = require('./App').default
19 |
20 | ReactDOM.render(
21 |
22 |
23 | ,
24 | mountPoint
25 | )
26 | })
27 | }
28 |
--------------------------------------------------------------------------------
/packages/sample-app/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 |
5 | const mountPoint = document.getElementById('root')
6 | ReactDOM.render(
7 | ,
10 | mountPoint
11 | )
12 |
--------------------------------------------------------------------------------
/packages/sample-app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "noImplicitAny": true,
5 | "removeComments": true,
6 | "preserveConstEnums": true,
7 | "sourceMap": true,
8 | "target": "es2015",
9 | "jsx": "react",
10 | "typeRoots": ["../../node_modules/@types"]
11 | },
12 | "compileOnSave": false
13 | }
14 |
--------------------------------------------------------------------------------
/packages/sample-app/webpack.config.babel.js:
--------------------------------------------------------------------------------
1 | const {
2 | createConfig,
3 |
4 | // Feature blocks
5 | addPlugins,
6 | entryPoint,
7 | env,
8 | group,
9 | performance,
10 | setMode,
11 | setOutput,
12 | sourceMaps,
13 |
14 | // Shorthand setters
15 | babel,
16 | css,
17 | devServer,
18 | extractText,
19 | typescript,
20 | postcss
21 | } = require('webpack-blocks')
22 |
23 | const HtmlWebpackPlugin = require('html-webpack-plugin')
24 | const path = require('path')
25 | const cssnano = require('cssnano')
26 |
27 | const developmentConfig = () =>
28 | group([
29 | sourceMaps(),
30 | devServer({
31 | proxy: {
32 | '/api/*': { target: 'http://localhost:4000' }
33 | }
34 | }),
35 | performance({
36 | // Increase performance budget thresholds for development mode
37 | maxAssetSize: 1500000,
38 | maxEntrypointSize: 1500000
39 | }),
40 | css.modules()
41 | ])
42 |
43 | const productionConfig = () =>
44 | group([
45 | css.modules(),
46 | postcss({
47 | plugins: [cssnano()]
48 | }),
49 | extractText('css/[name].[contenthash:hex:8].css')
50 | ])
51 |
52 | module.exports = createConfig([
53 | setMode(process.env.NODE_ENV || 'development'),
54 | babel(),
55 | typescript({ configFileName: path.resolve(__dirname, './tsconfig.json') }),
56 | addPlugins([
57 | new HtmlWebpackPlugin({
58 | inject: true,
59 | template: './index.html'
60 | })
61 | ]),
62 | env('development', [entryPoint('./src/index.dev.js'), developmentConfig()]),
63 | env('production', [
64 | entryPoint('./src/index.js'),
65 | setOutput('./build/bundle.js'),
66 | productionConfig()
67 | ])
68 | ])
69 |
--------------------------------------------------------------------------------
/packages/sass/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @webpack-blocks/sass - Changelog
2 |
3 | ## 2.0.0-alpha.1
4 |
5 | - Major version upgrade of `css-loader` to the
6 | [1.0.0](https://github.com/webpack-contrib/css-loader/releases/tag/v1.0.0)
7 | ([#291](https://github.com/andywer/webpack-blocks/pull/291))
8 | - Deprecate `minimize` option after
9 | [the css-loader removed it](https://github.com/webpack-contrib/css-loader/releases/tag/v1.0.0)
10 | ([#291](https://github.com/andywer/webpack-blocks/pull/291))
11 | - Remove `css-loader` and `style-loader` from the `use` option
12 | ([#294](https://github.com/andywer/webpack-blocks/pull/294))
13 |
14 | ## 2.0.0-alpha
15 |
16 | - Support for webpack 4 ([#261](https://github.com/andywer/webpack-blocks/pull/261))
17 |
18 | ## 1.0.0-rc
19 |
20 | - Add `minimize` option
21 |
22 | ## 1.0.0-beta.2
23 |
24 | - Update dependency versions
25 |
26 | ## 1.0.0-beta
27 |
28 | - Make compatible with `match()`
29 |
30 | ## 1.0.0-alpha
31 |
32 | - Updated for new core API ([#125](https://github.com/andywer/webpack-blocks/issues/125))
33 | - Requires node 6+
34 |
35 | ## 0.4.0
36 |
37 | - No changes, just keeping the version numbers in sync
38 |
39 | ## 0.3.0
40 |
41 | - Adapted to new API: Using `context` now
42 |
43 | ## 0.1.2
44 |
45 | - Allow setting custom `node-sass` options (see
46 | [#15](https://github.com/andywer/webpack-blocks/issues/15))
47 |
48 | ## 0.1.1
49 |
50 | - `loaders: [ 'style', 'css', 'sass' ]` =>
51 | `loaders: [ 'style-loader', 'css-loader', 'sass-loader' ]`
52 |
53 | ## 0.1.0
54 |
55 | Initial release.
56 |
--------------------------------------------------------------------------------
/packages/sass/README.md:
--------------------------------------------------------------------------------
1 | # webpack-blocks - Sass
2 |
3 | [](https://gitter.im/webpack-blocks)
4 | [](https://www.npmjs.com/package/@webpack-blocks/sass)
5 |
6 | This is the `sass` block providing Sass support for webpack. Uses `node-sass` via `sass-loader`.
7 |
8 | ## Usage
9 |
10 |
11 | ```js
12 | const { createConfig, match } = require('@webpack-blocks/webpack')
13 | const { css } = require('@webpack-blocks/assets')
14 | const sass = require('@webpack-blocks/sass')
15 |
16 | module.exports = createConfig([
17 | match(['*.scss', '!*node_modules*'], [
18 | css(),
19 | sass({ sassOptions: {/* node-sass options */} })
20 | ])
21 | ])
22 | ```
23 |
24 |
25 | **NOTE**: Use match() here to apply the css() block to `.scss` files.
26 |
27 | ## Options
28 |
29 | You can pass any [sass-loader](https://github.com/webpack-contrib/sass-loader) as an object to the
30 | `sass` block. For example you can pass
31 | [node-sass options](https://github.com/sass/node-sass#options) in the `sassOptions` property.
32 |
33 | ## Examples
34 |
35 | ### Extract text plugin
36 |
37 | Use the `extract-text` block to extract the compiled SASS/SCSS styles into a separate CSS file:
38 |
39 |
40 | ```js
41 | const { createConfig, match, env } = require('@webpack-blocks/webpack')
42 | const { css } = require('@webpack-blocks/assets')
43 | const sass = require('@webpack-blocks/sass')
44 | const extractText = require('@webpack-blocks/extract-text')
45 |
46 | module.exports = createConfig([
47 | match('*.scss', [
48 | css(),
49 | sass(),
50 | env('production', [extractText()])
51 | ])
52 | ])
53 | ```
54 |
55 |
56 | Make sure you use the `extract-text` block _after_ the `sass` block.
57 |
58 | ### CSS Modules
59 |
60 | You can use SASS/SCSS in combination with CSS modules.
61 |
62 |
63 | ```js
64 | const { createConfig, match } = require('@webpack-blocks/webpack')
65 | const { css } = require('@webpack-blocks/assets')
66 | const sass = require('@webpack-blocks/sass')
67 |
68 | module.exports = createConfig([
69 | match('*.scss', [
70 | css.modules(),
71 | sass()
72 | ])
73 | ])
74 | ```
75 |
76 |
77 | ### PostCSS
78 |
79 | You can use the SASS block together with PostCSS (using the `postcss` block) and its plugins, like
80 | the [Autoprefixer](https://github.com/postcss/autoprefixer), or
81 | [cssnano](https://github.com/cssnano/cssnano) if you want css minification.
82 |
83 |
84 | ```js
85 | const { createConfig, match } = require('@webpack-blocks/webpack')
86 | const { css } = require('@webpack-blocks/assets')
87 | const sass = require('@webpack-blocks/sass')
88 | const postcss = require('@webpack-blocks/postcss')
89 | const autoprefixer = require('autoprefixer')
90 | const cssnano = require('cssnano')
91 |
92 | module.exports = createConfig([
93 | match('*.scss', [
94 | css(),
95 | sass(),
96 | postcss([autoprefixer(), cssnano()])
97 | ])
98 | ])
99 | ```
100 |
101 |
102 | ## webpack-blocks
103 |
104 | Check out the
105 |
106 | 👉 [Main documentation](https://github.com/andywer/webpack-blocks)
107 |
108 | Released under the terms of the MIT license.
109 |
--------------------------------------------------------------------------------
/packages/sass/__tests__/integration.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import { css } from '@webpack-blocks/assets'
3 | import { createConfig, match } from '@webpack-blocks/core'
4 | import sass from '../index'
5 |
6 | test('Sass works with defaults, inside match()', t => {
7 | const config = createConfig({}, [match('*.sass', [sass()])])
8 |
9 | t.deepEqual(config.module.rules, [
10 | {
11 | test: /^.*\.sass$/,
12 | use: [
13 | {
14 | loader: 'sass-loader',
15 | options: {}
16 | }
17 | ]
18 | }
19 | ])
20 | })
21 |
22 | test('Sass works with css()', t => {
23 | const config = createConfig({}, [match('*.sass', { exclude: /node_modules/ }, [css(), sass()])])
24 |
25 | t.deepEqual(config.module.rules, [
26 | {
27 | test: /^.*\.sass$/,
28 | exclude: /node_modules/,
29 | use: [
30 | {
31 | loader: 'style-loader',
32 | options: {}
33 | },
34 | {
35 | loader: 'css-loader',
36 | options: {}
37 | },
38 | {
39 | loader: 'sass-loader',
40 | options: {}
41 | }
42 | ]
43 | }
44 | ])
45 | })
46 |
47 | test('Sass should pass sourceMap option to sass-loader', t => {
48 | const config = createConfig({}, [match('*.sass', [sass({ sourceMap: true })])])
49 |
50 | t.deepEqual(config.module.rules, [
51 | {
52 | test: /^.*\.sass$/,
53 | use: [
54 | {
55 | loader: 'sass-loader',
56 | options: {
57 | sourceMap: true
58 | }
59 | }
60 | ]
61 | }
62 | ])
63 | })
64 |
--------------------------------------------------------------------------------
/packages/sass/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SASS webpack block.
3 | *
4 | * @see https://github.com/jtangelder/sass-loader
5 | */
6 |
7 | module.exports = sass
8 |
9 | /**
10 | * @param {object} [options] See https://github.com/sass/node-sass#options
11 | * @param {string[]} [options.sassOptions.includePaths]
12 | * @param {bool} [options.sassOptions.indentedSyntax]
13 | * @param {string} [options.sassOptions.outputStyle]
14 | * @param {bool} [options.sourceMap]
15 | * @return {Function}
16 | */
17 | function sass(options = {}) {
18 | return (context, util) => {
19 | if (!context.match) {
20 | throw Error(
21 | 'You cannot use the sass() block outside a match() block. You also need to use the css() block on sass files.'
22 | )
23 | }
24 |
25 | return util.addLoader(
26 | Object.assign(
27 | {
28 | test: /\.(sass|scss)$/,
29 | use: [
30 | {
31 | loader: 'sass-loader',
32 | options
33 | }
34 | ]
35 | },
36 | context.match
37 | )
38 | )
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/packages/sass/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@webpack-blocks/sass",
3 | "version": "2.1.0",
4 | "description": "Webpack block for SASS.",
5 | "main": "lib/index",
6 | "license": "MIT",
7 | "author": "Andy Wermke ",
8 | "engines": {
9 | "node": ">= 8.9.0"
10 | },
11 | "keywords": [
12 | "webpack",
13 | "webpack-blocks"
14 | ],
15 | "repository": "andywer/webpack-blocks",
16 | "bugs": "https://github.com/andywer/webpack-blocks/issues",
17 | "dependencies": {
18 | "css-loader": "^3.5.2",
19 | "lodash": "^4.17.15",
20 | "node-sass": "^4.13.1",
21 | "sass-loader": "^8.0.2",
22 | "style-loader": "^1.1.4"
23 | },
24 | "devDependencies": {
25 | "@webpack-blocks/assets": "^2.1.0",
26 | "@webpack-blocks/core": "^2.1.0",
27 | "webpack": "^4.20.2"
28 | },
29 | "peerDependencies": {
30 | "@webpack-blocks/core": "^2.0.0"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/packages/tslint/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @webpack-blocks/tslint - Changelog
2 |
3 | ## 2.0.0-alpha
4 |
5 | - Support for webpack 4 ([#261](https://github.com/andywer/webpack-blocks/pull/261))
6 |
7 | ## 1.0.0-beta.2
8 |
9 | - Update dependency versions
10 |
11 | ## 1.0.0-beta
12 |
13 | - Make compatible with `match()`
14 |
15 | ## 1.0.0-alpha
16 |
17 | - Updated for new core API ([#125](https://github.com/andywer/webpack-blocks/issues/125))
18 | - Requires node 6+
19 |
20 | ## 0.4.0
21 |
22 | - No changes, just keeping the version numbers in sync
23 |
24 | ## 0.1.0
25 |
26 | Initial release.
27 |
--------------------------------------------------------------------------------
/packages/tslint/README.md:
--------------------------------------------------------------------------------
1 | # webpack-blocks - TSLint
2 |
3 | [](https://gitter.im/webpack-blocks)
4 | [](https://www.npmjs.com/package/@webpack-blocks/tslint)
5 |
6 | This is the `tslint` block providing TypeScript linting support for webpack. Uses `tslint` via
7 | `tslint-loader`.
8 |
9 | ## Usage
10 |
11 |
12 | ```js
13 | const { createConfig } = require('@webpack-blocks/webpack')
14 | const tslint = require('@webpack-blocks/tslint')
15 |
16 | module.exports = createConfig([
17 | tslint(/* tslint options */)
18 | ])
19 | ```
20 |
21 |
22 | Use `match()` to explicitly specify the files to lint.
23 |
24 | ## Options
25 |
26 | You can pass random `ts-loader` options as an object to the `tslint` block. See
27 | [tslint-loader options](https://github.com/wbuchwalter/tslint-loader#usage).
28 |
29 | ## webpack-blocks
30 |
31 | Check out the
32 |
33 | 👉 [Main documentation](https://github.com/andywer/webpack-blocks)
34 |
35 | Released under the terms of the MIT license.
36 |
--------------------------------------------------------------------------------
/packages/tslint/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Tslint webpack block.
3 | *
4 | * @see https://github.com/wbuchwalter/tslint-loader
5 | */
6 |
7 | module.exports = tslint
8 |
9 | /**
10 | * @param {object} [options] See https://github.com/wbuchwalter/tslint-loader#usage
11 | * @return {Function}
12 | */
13 | function tslint(options = {}) {
14 | return (context, util) => prevConfig => {
15 | let nextConfig = util.addLoader(
16 | Object.assign(
17 | {
18 | test: /\.(ts|tsx)$/,
19 | use: ['tslint-loader'],
20 | enforce: 'pre'
21 | },
22 | context.match
23 | )
24 | )(prevConfig)
25 |
26 | nextConfig = util.addPlugin(
27 | new context.webpack.LoaderOptionsPlugin({
28 | options: {
29 | tslint: options
30 | }
31 | })
32 | )(nextConfig)
33 |
34 | return nextConfig
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/packages/tslint/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@webpack-blocks/tslint",
3 | "version": "2.0.1",
4 | "description": "Webpack block for typescript linting.",
5 | "main": "lib/index",
6 | "license": "MIT",
7 | "author": "Jan van Brügge ",
8 | "engines": {
9 | "node": ">= 6.0"
10 | },
11 | "keywords": [
12 | "webpack",
13 | "webpack-blocks"
14 | ],
15 | "repository": "andywer/webpack-blocks",
16 | "bugs": "https://github.com/andywer/webpack-blocks/issues",
17 | "dependencies": {
18 | "tslint": "^5.17.0",
19 | "tslint-loader": "^3.6.0",
20 | "typescript": "^3.1.2"
21 | },
22 | "peerDependencies": {
23 | "@webpack-blocks/core": "^2.0.0"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/packages/typescript/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @webpack-blocks/typescript - Changelog
2 |
3 | ## 2.0.0-alpha
4 |
5 | - Support for webpack 4 ([#261](https://github.com/andywer/webpack-blocks/pull/261))
6 |
7 | ## 1.0.0-beta.2
8 |
9 | - Update dependency versions
10 |
11 | ## 1.0.0-beta
12 |
13 | - Make compatible with `match()`
14 |
15 | ## 1.0.0-alpha
16 |
17 | - Updated for new core API ([#125](https://github.com/andywer/webpack-blocks/issues/125))
18 | - Requires node 6+
19 |
20 | ## 0.4.1
21 |
22 | - Allow passing custom loader options (see
23 | [#141](https://github.com/andywer/webpack-blocks/pull/141))
24 |
25 | ## 0.4.0
26 |
27 | - No changes, just keeping the version numbers in sync
28 |
29 | ## 0.1.0
30 |
31 | Initial release.
32 |
--------------------------------------------------------------------------------
/packages/typescript/README.md:
--------------------------------------------------------------------------------
1 | # webpack-blocks - TypeScript
2 |
3 | [](https://gitter.im/webpack-blocks)
4 | [](https://www.npmjs.com/package/@webpack-blocks/typescript)
5 |
6 | This is the `typescript` block providing TypeScript support for webpack. Uses
7 | `awesome-typescript-loader`.
8 |
9 | ## Usage
10 |
11 |
12 | ```js
13 | const { createConfig } = require('@webpack-blocks/webpack')
14 | const typescript = require('@webpack-blocks/typescript')
15 |
16 | module.exports = createConfig([
17 | typescript(/* options, optional */)
18 | ])
19 | ```
20 |
21 |
22 | Use `match()` to explicitly specify the files to load using the TypeScript loader.
23 |
24 | ## Options
25 |
26 | Uses the default tsconfig.json in the root directory (See
27 | [here](https://github.com/s-panferov/awesome-typescript-loader#tsconfigjson)). You can pass
28 | [awesome-typescript-loader options](https://github.com/s-panferov/awesome-typescript-loader#loader-options)
29 | to the block.
30 |
31 | ## webpack-blocks
32 |
33 | Check out the
34 |
35 | 👉 [Main documentation](https://github.com/andywer/webpack-blocks)
36 |
37 | Released under the terms of the MIT license.
38 |
--------------------------------------------------------------------------------
/packages/typescript/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Typescript webpack block.
3 | *
4 | * @see https://github.com/s-panferov/awesome-typescript-loader
5 | */
6 |
7 | const { CheckerPlugin, TsConfigPathsPlugin } = require('awesome-typescript-loader')
8 |
9 | module.exports = typescript
10 |
11 | /**
12 | * @param {object} [options] See https://github.com/s-panferov/awesome-typescript-loader#loader-options
13 | * @return {Function}
14 | */
15 | function typescript(options = {}) {
16 | return (context, util) =>
17 | util.merge({
18 | resolve: {
19 | extensions: ['.ts', '.tsx']
20 | },
21 | module: {
22 | rules: [
23 | Object.assign(
24 | {
25 | test: /\.(ts|tsx)$/,
26 | use: [
27 | {
28 | loader: 'awesome-typescript-loader',
29 | options
30 | }
31 | ]
32 | },
33 | context.match
34 | )
35 | ]
36 | },
37 | plugins: [
38 | new CheckerPlugin(),
39 | new TsConfigPathsPlugin({ tsconfig: options.configFileName, compiler: options.compiler }) // This hooks into webpacks module resolution, configure via tsconfig.json
40 | ]
41 | })
42 | }
43 |
--------------------------------------------------------------------------------
/packages/typescript/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@webpack-blocks/typescript",
3 | "version": "2.0.1",
4 | "description": "Webpack block for Typescript.",
5 | "main": "lib/index",
6 | "license": "MIT",
7 | "author": "Jan van Brügge ",
8 | "engines": {
9 | "node": ">= 6.0"
10 | },
11 | "keywords": [
12 | "webpack",
13 | "webpack-blocks"
14 | ],
15 | "repository": "andywer/webpack-blocks",
16 | "bugs": "https://github.com/andywer/webpack-blocks/issues",
17 | "dependencies": {
18 | "awesome-typescript-loader": "^5.2.1",
19 | "typescript": "^3.1.2"
20 | },
21 | "peerDependencies": {
22 | "@webpack-blocks/core": "^2.0.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/uglify/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @webpack-blocks/uglify - Changelog
2 |
3 | ## 2.0.0-alpha
4 |
5 | - Support for webpack 4 ([#261](https://github.com/andywer/webpack-blocks/pull/261))
6 |
7 | ## 1.1.0
8 |
9 | - Use `uglifyjs-webpack-plugin` v1.0 (not the beta)
10 | ([#231](https://github.com/andywer/webpack-blocks/issues/231))
11 |
12 | ## 1.0.0
13 |
14 | Initial release.
15 |
--------------------------------------------------------------------------------
/packages/uglify/README.md:
--------------------------------------------------------------------------------
1 | # webpack-blocks - UglifyJS
2 |
3 | [](https://gitter.im/webpack-blocks)
4 | [](https://www.npmjs.com/package/@webpack-blocks/uglify)
5 |
6 | This block provides UglifyJS webpack plugin configuration for
7 | [webpack-blocks](https://github.com/andywer/webpack-blocks).
8 |
9 | Based on [uglifyjs-webpack-plugin](https://github.com/webpack-contrib/uglifyjs-webpack-plugin) (not
10 | `webpack.optimize.UglifyJsPlugin`) which uses UglifyJS v3 (uglify-es) that supports ECMAScript 2015.
11 |
12 | **This block will only work in the `production` mode.**
13 |
14 | ## Usage
15 |
16 |
17 | ```js
18 | const { createConfig, env, uglify } = require('webpack-blocks')
19 |
20 | module.exports = createConfig([
21 | uglify(/* options */)
22 | ])
23 | ```
24 |
25 |
26 | ## Options
27 |
28 | You can pass any `uglifyjs-webpack-plugin` and UglifyJS options, see the
29 | [`uglifyjs-webpack-plugin` docs for details](https://github.com/webpack-contrib/uglifyjs-webpack-plugin#options).
30 |
31 | ## Generated webpack config
32 |
33 | By default generates this configuration:
34 |
35 | ```js
36 | {
37 | optimization: {
38 | minimizer: [
39 | new UglifyJSPlugin({
40 | parallel: true,
41 | cache: true,
42 | uglifyOptions: {
43 | compress: {
44 | warnings: false
45 | }
46 | }
47 | })
48 | ]
49 | }
50 | }
51 | ```
52 |
53 | ## webpack-blocks
54 |
55 | Check out the
56 |
57 | 👉 [Main documentation](https://github.com/andywer/webpack-blocks)
58 |
59 | Released under the terms of the MIT license.
60 |
--------------------------------------------------------------------------------
/packages/uglify/__tests__/uglify.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import UglifyJSPlugin from 'uglifyjs-webpack-plugin'
3 | import { createConfig } from '@webpack-blocks/core'
4 | import uglify from '../index'
5 |
6 | test('Uglify default options work', t => {
7 | const config = createConfig({}, [uglify()])
8 |
9 | t.true(config.optimization.minimizer[0] instanceof UglifyJSPlugin)
10 | })
11 |
12 | test('Uglify options work', t => {
13 | const config = createConfig({}, [
14 | uglify({
15 | parallel: 42
16 | })
17 | ])
18 |
19 | t.truthy(config.optimization.minimizer[0].options.parallel)
20 | t.truthy(config.optimization.minimizer[0].options.cache)
21 | t.deepEqual(config.optimization.minimizer[0].options.parallel, 42)
22 | t.deepEqual(config.optimization.minimizer[0].options.cache, true)
23 | })
24 |
--------------------------------------------------------------------------------
/packages/uglify/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * UglifyJS webpack block.
3 | *
4 | * @see https://github.com/webpack-contrib/uglifyjs-webpack-plugin
5 | */
6 |
7 | const webpackMerge = require('webpack-merge')
8 | const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
9 |
10 | module.exports = uglify
11 |
12 | /**
13 | * @param {object} [options] UglifyJS options
14 | * @return {Function}
15 | */
16 | function uglify(options = {}) {
17 | options = webpackMerge(
18 | {
19 | parallel: true,
20 | cache: true,
21 | uglifyOptions: {
22 | compress: {
23 | warnings: false
24 | }
25 | }
26 | },
27 | options
28 | )
29 |
30 | const postHook = (context, util) => {
31 | const plugin = new UglifyJSPlugin(options)
32 | return util.merge({
33 | optimization: {
34 | minimizer: [plugin]
35 | }
36 | })
37 | }
38 |
39 | return Object.assign(() => prevConfig => prevConfig, { post: postHook })
40 | }
41 |
--------------------------------------------------------------------------------
/packages/uglify/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@webpack-blocks/uglify",
3 | "version": "2.1.0",
4 | "description": "Webpack block for UglifyJS",
5 | "main": "index",
6 | "license": "MIT",
7 | "author": "Artem Sapegin ",
8 | "engines": {
9 | "node": ">= 6.0"
10 | },
11 | "keywords": [
12 | "webpack",
13 | "webpack-blocks",
14 | "uglify",
15 | "uglifyjs"
16 | ],
17 | "repository": "andywer/webpack-blocks",
18 | "bugs": "https://github.com/andywer/webpack-blocks/issues",
19 | "dependencies": {
20 | "uglifyjs-webpack-plugin": "^1.3.0",
21 | "webpack-merge": "^4.2.2"
22 | },
23 | "devDependencies": {
24 | "@webpack-blocks/core": "^2.1.0",
25 | "webpack": "^4.20.2"
26 | },
27 | "peerDependencies": {
28 | "@webpack-blocks/core": "^2.0.0"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/packages/webpack-blocks/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @webpack-blocks/webpack - Changelog
2 |
3 | ## 2.0.0-alpha
4 |
5 | - Support for webpack 4 ([#261](https://github.com/andywer/webpack-blocks/pull/261))
6 |
7 | ## 1.0.0-rc.2
8 |
9 | - Updated `@webpack-blocks/uglify` to `v1.1.0`
10 |
11 | ## 1.0.0-rc
12 |
13 | - Renamed `babel6` to `babel`
14 | - The new version of `extract-text` requires webpack v3
15 |
16 | ## 1.0.0-beta.4
17 |
18 | - Add `@webpack-blocks/uglify`
19 |
20 | ## 1.0.0-beta.3
21 |
22 | - Updated `@webpack-blocks/dev-server` to `v1.0.0-beta.2`
23 |
24 | ## 1.0.0-beta.2
25 |
26 | - Updated `@webpack-blocks/webpack` to `v1.0.0-beta.2`
27 |
28 | ## 1.0.0-beta
29 |
30 | - Updated dependency versions only
31 |
32 | ## 1.0.0-alpha
33 |
34 | - Initial release
35 |
--------------------------------------------------------------------------------
/packages/webpack-blocks/README.md:
--------------------------------------------------------------------------------
1 | # webpack-blocks - the convenience package
2 |
3 | [](https://gitter.im/webpack-blocks)
4 | [](https://www.npmjs.com/package/webpack-blocks)
5 |
6 | This is the webpack-blocks convenience package. It wraps all the most commonly used blocks, so you
7 | can install just this single package and have webpack-blocks and your favorite blocks set up.
8 |
9 | ## Usage
10 |
11 | Here is a small sample configuration. Instead of requiring from `@webpack-blocks/webpack`,
12 | `@webpack-blocks/babel` and others you just need a single `require()` and a single dependency in
13 | your `package.json`.
14 |
15 | Of course you can still separately define or install custom blocks and use them as you want.
16 |
17 | ```js
18 | const webpack = require('webpack')
19 | const {
20 | babel,
21 | createConfig,
22 | css,
23 | defineConstants,
24 | entryPoint,
25 | env,
26 | extractText,
27 | match,
28 | setOutput,
29 | uglify,
30 | postcss
31 | } = require('webpack-blocks')
32 | const cssnano = require('cssnano')
33 |
34 | module.exports = createConfig([
35 | entryPoint('./src/main.js'),
36 | setOutput('./build/bundle.js'),
37 | babel(),
38 | defineConstants({
39 | 'process.env.NODE_ENV': process.env.NODE_ENV
40 | }),
41 | match('*.css', { exclude: /node_modules/ }, [
42 | css(),
43 | env('production', [
44 | extractText(),
45 | postcss({
46 | plugins: [cssnano()]
47 | })
48 | ])
49 | ]),
50 | env('production', [uglify()])
51 | ])
52 | ```
53 |
54 | ## Included blocks
55 |
56 | - [assets](https://github.com/andywer/webpack-blocks/tree/master/packages/assets)
57 | - [babel](https://github.com/andywer/webpack-blocks/tree/master/packages/babel)
58 | - [dev-server](https://github.com/andywer/webpack-blocks/tree/master/packages/dev-server)
59 | - [extract-text](https://github.com/andywer/webpack-blocks/tree/master/packages/extract-text)
60 | - [postcss](https://github.com/andywer/webpack-blocks/tree/master/packages/postcss)
61 | - [sass](https://github.com/andywer/webpack-blocks/tree/master/packages/sass)
62 | - [typescript](https://github.com/andywer/webpack-blocks/tree/master/packages/typescript)
63 | - [uglify](https://github.com/andywer/webpack-blocks/tree/master/packages/uglify)
64 | - [webpack](https://github.com/andywer/webpack-blocks/tree/master/packages/webpack)
65 |
66 | ## webpack-blocks
67 |
68 | Check out the
69 |
70 | 👉 [Main documentation](https://github.com/andywer/webpack-blocks)
71 |
72 | Released under the terms of the MIT license.
73 |
--------------------------------------------------------------------------------
/packages/webpack-blocks/index.js:
--------------------------------------------------------------------------------
1 | const assets = require('@webpack-blocks/assets')
2 | const babel = require('@webpack-blocks/babel')
3 | const devServer = require('@webpack-blocks/dev-server')
4 | const extractText = require('@webpack-blocks/extract-text')
5 | const postcss = require('@webpack-blocks/postcss')
6 | const sass = require('@webpack-blocks/sass')
7 | const typescript = require('@webpack-blocks/typescript')
8 | const uglify = require('@webpack-blocks/uglify')
9 | const webpack = require('@webpack-blocks/webpack')
10 |
11 | module.exports = Object.assign({}, assets, webpack, {
12 | babel,
13 | devServer,
14 | extractText,
15 | postcss,
16 | sass,
17 | typescript,
18 | uglify
19 | })
20 |
--------------------------------------------------------------------------------
/packages/webpack-blocks/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-blocks",
3 | "version": "2.1.0",
4 | "description": "Convenience package that includes all the most common webpack blocks.",
5 | "license": "MIT",
6 | "author": "Andy Wermke ",
7 | "engines": {
8 | "node": ">= 6.0"
9 | },
10 | "keywords": [
11 | "webpack",
12 | "webpack-blocks"
13 | ],
14 | "repository": "andywer/webpack-blocks",
15 | "bugs": "https://github.com/andywer/webpack-blocks/issues",
16 | "dependencies": {
17 | "@webpack-blocks/assets": "^2.1.0",
18 | "@webpack-blocks/babel": "^2.1.0",
19 | "@webpack-blocks/dev-server": "^2.1.0",
20 | "@webpack-blocks/extract-text": "^2.1.0",
21 | "@webpack-blocks/postcss": "^2.1.0",
22 | "@webpack-blocks/sass": "^2.1.0",
23 | "@webpack-blocks/typescript": "^2.0.1",
24 | "@webpack-blocks/uglify": "^2.1.0",
25 | "@webpack-blocks/webpack": "^2.1.0"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/packages/webpack/.npmignore:
--------------------------------------------------------------------------------
1 | __e2e-fixtures__/
2 | __tests__/
3 |
--------------------------------------------------------------------------------
/packages/webpack/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @webpack-blocks/webpack - Changelog
2 |
3 | ## 2.0.0-alpha
4 |
5 | - Remove deprecated `fileType` API ([#260](https://github.com/andywer/webpack-blocks/issues/260))
6 | - Remove deprecated `resolveAliases` block
7 | ([#267](https://github.com/andywer/webpack-blocks/issues/267))
8 | - Support for webpack 4 ([#261](https://github.com/andywer/webpack-blocks/pull/261))
9 | - Added `setMode()` and `optimization()` blocks
10 | ([#274](https://github.com/andywer/webpack-blocks/issues/274))
11 |
12 | ## 1.0.0
13 |
14 | - Added `when()` ([#242](https://github.com/andywer/webpack-blocks/issues/242))
15 |
16 | ## 1.0.0-rc
17 |
18 | - Added `setEnv()` ([#206](https://github.com/andywer/webpack-blocks/pull/206))
19 |
20 | ## 1.0.0-beta.3
21 |
22 | - Make resolve() prepend custom extensions
23 | ([#177](https://github.com/andywer/webpack-blocks/issues/177))
24 | - Let core `createConfig()` validate the passed setters
25 | ([#171](https://github.com/andywer/webpack-blocks/issues/171))
26 |
27 | ## 1.0.0-beta.2
28 |
29 | - Made webpack a peer dependency ([#169](https://github.com/andywer/webpack-blocks/issues/169))
30 | - Made compatible with webpack v3 ([#169](https://github.com/andywer/webpack-blocks/issues/169))
31 |
32 | ## 1.0.0-beta
33 |
34 | - Added `match()`
35 | - Added `resolve()`, deprecate `resolveAliases()`
36 |
37 | ## 1.0.0-alpha
38 |
39 | - Updated for new core API ([#125](https://github.com/andywer/webpack-blocks/issues/125))
40 | - Fail with meaningful message if `createConfig()` is called with invalid param
41 | ([#110](https://github.com/andywer/webpack-blocks/issues/110))
42 | - Added `text/html` file type (in `@webpack-blocks/core`)
43 | - Requires node 6+
44 |
45 | ## 0.4.0
46 |
47 | - Provide `createConfig.vanilla()` (see [#80](https://github.com/andywer/webpack-blocks/issues/80))
48 | - Added `webpackVersion` to context
49 | - Breaking change: Removed `node_modules/` exclusion from default css-loader
50 | - Using `webpack-merge` v2.3 instead of v0.14
51 | - Using `webpack` v2.2 instead of its RC
52 |
53 | ## 0.3.1
54 |
55 | - Remove the `json-loader` config & depedency, since webpack 2 comes with a default json-loader
56 | config (#63)
57 |
58 | ## 0.3.0
59 |
60 | Initial non-beta release. Aligned with the v0.3 release changes.
61 |
62 | - Provide `group()` for creating presets
63 | - Provide `performance()` for webpack performance budgeting
64 | - Updated dependency: Using webpack 2 release candidate
65 |
66 | ## 0.1.0-beta
67 |
68 | Initial beta release.
69 |
--------------------------------------------------------------------------------
/packages/webpack/README.md:
--------------------------------------------------------------------------------
1 | # webpack-blocks - webpack base configuration
2 |
3 | [](https://gitter.im/webpack-blocks)
4 | [](https://www.npmjs.com/package/@webpack-blocks/webpack)
5 |
6 | This is the `webpack` block providing webpack core functionality. Also provides all
7 | `@webpack-blocks/core` exports for convenience.
8 |
9 | ## Usage
10 |
11 | ```js
12 | const HtmlWebpackPlugin = require('html-webpack-plugin')
13 | const {
14 | addPlugins,
15 | createConfig,
16 | entryPoint,
17 | env,
18 | setMode,
19 | setOutput,
20 | sourceMaps
21 | } = require('@webpack-blocks/webpack')
22 | const { css } = require('@webpack-blocks/assets')
23 |
24 | module.exports = createConfig([
25 | setMode(process.env.NODE_ENV || 'development'),
26 | entryPoint('./src/main.js'),
27 | setOutput('./build/bundle.js'),
28 | css(),
29 | addPlugins([
30 | new HtmlWebpackPlugin({
31 | inject: true,
32 | template: './index.html'
33 | })
34 | ]),
35 | env('development', [
36 | // will only enable source maps if `NODE_ENV === 'development'`
37 | sourceMaps()
38 | ])
39 | ])
40 | ```
41 |
42 | ## Exports
43 |
44 | #### createConfig(configSetter: Function[]): object
45 |
46 | Takes an array of config setters (the functions returned by invoked webpack blocks), invokes them
47 | and returns the resulting webpack config object.
48 |
49 | ### Helpers
50 |
51 | #### group(configSetters: Function[]): Function
52 |
53 | Combines an array of blocks to a new joined block. Running this single block has the same effect as
54 | running all source blocks.
55 |
56 | #### env(envName: string, configSetters: Function[]): Function
57 |
58 | Applies an array of webpack blocks only if `process.env.NODE_ENV` matches the given `envName`. If no
59 | `NODE_ENV` is set, it will be treated as 'development'.
60 |
61 | Use like this:
62 |
63 |
64 | ```js
65 | module.exports = createConfig([
66 | css(),
67 | env('production', [extractText()])
68 | ])
69 | ```
70 |
71 |
72 | #### match(test: string|RegExp|Array, options: ?object, configSetters: Function[]): Function
73 |
74 | State on which files to apply the loader blocks passed in this call. Works like `group()`, but adds
75 | the file matching information to the context that can be used by the child blocks. The options
76 | parameter is optional.
77 |
78 | Use like this:
79 |
80 |
81 | ```js
82 | module.exports = createConfig([
83 | match(['*.scss', '!*node_modules*'], [
84 | sass(),
85 | extractText('css/[name].css')
86 | ])
87 | ])
88 | ```
89 |
90 |
91 | To match multiple file patterns you can pass a pattern array:
92 |
93 |
94 | ```js
95 | module.exports = createConfig([
96 | match(['*.sass', '*.scss'], [
97 | /* blocks */
98 | ])
99 | ])
100 | ```
101 |
102 |
103 | #### when(condition: boolean, configSetters: Function[]): Function
104 |
105 | Applies an array of webpack blocks only if `condition` is true (or truthy).
106 |
107 | Use like this:
108 |
109 |
110 | ```js
111 | module.exports = createConfig([
112 | when(process.env.CI, [reportBuildStatsPlugin()])
113 | ])
114 | ```
115 |
116 |
117 | ### Shorthand setters
118 |
119 | #### addPlugins(plugins: WebpackPlugin[])
120 |
121 | Add custom [plugins](https://webpack.github.io/docs/configuration.html#plugins) to the webpack
122 | configuration.
123 |
124 | Example usage:
125 |
126 | ```js
127 | addPlugins([new HtmlWebpackPlugin()])
128 | ```
129 |
130 | #### customConfig(webpackConfigSnippet: object)
131 |
132 | Add some custom configuration to the webpack configuration. The object you pass will be merged into
133 | the webpack configuration object.
134 |
135 | #### defineConstants(constants: object): Function
136 |
137 | Replaces constants in your source code with a value (`process.env.NODE_ENV` for example) using the
138 | [webpack.DefinePlugin](https://webpack.github.io/docs/list-of-plugins.html#defineplugin). Pass an
139 | object containing your constant definitions: `{ [constantName: string]: }`.
140 |
141 | Every constant's value is `JSON.stringify()`-ed first, so you don't have to remember.
142 |
143 | Using `defineConstants` multiple times results in a single DefinePlugin instance configured to do
144 | all the replacements.
145 |
146 | #### setEnv(constants: string[]|object): Function
147 |
148 | Replaces constants in your source code with a values from `process.env` using the
149 | [webpack.EnvironmentPlugin](https://webpack.js.org/plugins/environment-plugin/).
150 |
151 | Using `setEnv` multiple times results in a single EnvironmentPlugin instance configured to do all
152 | the replacements.
153 |
154 | ```js
155 | module.exports = createConfig([
156 | setEnv(['NODE_ENV']),
157 | setEnv({
158 | BABEL_ENV: 'development', // use 'development' unless process.env.BABEL_ENV is defined
159 | PORT: 3000
160 | })
161 | ])
162 | ```
163 |
164 | #### entryPoint(entryPoint: string|string[]|object)
165 |
166 | Adds one or multiple entry points. If the parameter is not an object the entry point(s) will be
167 | added to the default chunk named `main`. This way we make sure that the resulting
168 | [https://webpack.github.io/docs/configuration.html#entry](entry) configuration property will always
169 | be an object.
170 |
171 | #### optimization(optimizationOptions: object)
172 |
173 | Set the optimization [settings](https://webpack.js.org/configuration/optimization/).
174 |
175 | #### performance(perfBudgetOptions: object)
176 |
177 | Set a performance budget. Performance budgets are custom limits (like max bundle size) you can set
178 | to make webpack warn you or throw an error if the application exceeds those limits.
179 |
180 | Options object:
181 |
182 | ```js
183 | {
184 | maxAssetSize: number, // File size limit in bytes
185 | maxEntrypointSize: number, // Total size (of an entry point) limit in bytes
186 | hints: string // "warning" or "error"
187 | }
188 | ```
189 |
190 | #### resolve(config: object)
191 |
192 | Sets [resolve](https://webpack.js.org/configuration/resolve/). Use it to manually override module
193 | resolution.
194 |
195 | Example:
196 |
197 | ```js
198 | resolve({
199 | // resolve `import 'Utilities'` to correct path
200 | alias: { Utilities: path.resolve(__dirname, 'src/utilities/') },
201 | extensions: ['.js', '.json'],
202 | modules: [path.resolve(__dirname, 'src'), 'node_modules']
203 | })
204 | ```
205 |
206 | #### setContext(path: string)
207 |
208 | Sets the webpack [context](https://webpack.github.io/docs/configuration.html#context). Not to be
209 | confused with the webpack-block's `context` object.
210 |
211 | #### setDevTool(devtool: string)
212 |
213 | Use it to manually set the webpack
214 | [devtool](https://webpack.github.io/docs/configuration.html#devtool) property, like `'eval'`,
215 | `'source-map'` and such.
216 |
217 | #### setMode(mode: string)
218 |
219 | Sets the webpack [mode](https://webpack.js.org/concepts/mode).
220 |
221 | #### setOutput(output: string|object)
222 |
223 | Sets the webpack [output](https://webpack.github.io/docs/configuration.html#output) property. Use it
224 | to tell webpack where to save the output bundle(s).
225 |
226 | You can either pass an object that complies to the format described in the
227 | [webpack docs](https://webpack.github.io/docs/configuration.html#output) or just pass the
228 | destination file path.
229 |
230 | Instead of passing the destination file path you can also
231 |
232 | - Just pass a filename (not the complete path): The directory will default to `./build/`.
233 | - Just pass the path to a directory (trailing `/`): The filename will default to `bundle.js`.
234 |
235 | #### sourceMaps(devtool: ?string)
236 |
237 | Just a convenience wrapper to enable sourcemaps in an easier-to-read fashion than `setDevTool()`.
238 | Will set webpack's `devtool` to `'cheap-module-eval-source-map'` if no explicit `devtool` is passed
239 | as parameter.
240 |
241 | ## webpack-blocks
242 |
243 | Check out the
244 |
245 | 👉 [Main documentation](https://github.com/andywer/webpack-blocks)
246 |
247 | Released under the terms of the MIT license.
248 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/babel-postcss-extract-text/app.js:
--------------------------------------------------------------------------------
1 | require('./styles.css')
2 |
3 | module.exports = process.env.TEST
4 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/babel-postcss-extract-text/styles.css:
--------------------------------------------------------------------------------
1 | $MARGIN: 40px;
2 |
3 | .app {
4 | margin: $MARGIN;
5 | }
6 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/babel-postcss-extract-text/webpack.config.js:
--------------------------------------------------------------------------------
1 | const {
2 | createConfig,
3 | defineConstants,
4 | entryPoint,
5 | match,
6 | performance,
7 | setDevTool,
8 | setMode,
9 | setOutput
10 | } = require('../../index')
11 |
12 | const babel = require('@webpack-blocks/babel')
13 | const postcss = require('@webpack-blocks/postcss')
14 | const extractText = require('@webpack-blocks/extract-text')
15 | const { css } = require('@webpack-blocks/assets')
16 | const path = require('path')
17 | const postcssVars = require('postcss-simple-vars')
18 |
19 | module.exports = createConfig([
20 | setMode('development'),
21 | setDevTool(false),
22 | entryPoint(path.join(__dirname, 'app.js')),
23 | setOutput(path.join(__dirname, 'build/bundle.js')),
24 | babel(),
25 | match('*.css', [
26 | css(),
27 | postcss({
28 | plugins: [postcssVars]
29 | }),
30 | extractText('styles.css')
31 | ]),
32 | performance({
33 | maxAssetSize: 100000,
34 | maxEntrypointSize: 500000,
35 | hints: 'error'
36 | }),
37 | defineConstants({
38 | 'process.env.TEST': 'This is the injected process.env.TEST!'
39 | })
40 | ])
41 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/minimal/app.js:
--------------------------------------------------------------------------------
1 | module.exports = 'I am the minimal test export'
2 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/minimal/webpack.config.js:
--------------------------------------------------------------------------------
1 | const { createConfig, customConfig, entryPoint, setMode, setOutput } = require('../../index')
2 |
3 | const path = require('path')
4 |
5 | module.exports = createConfig([
6 | setMode('development'),
7 | entryPoint(path.join(__dirname, 'app.js')),
8 | setOutput(path.join(__dirname, 'build/bundle.js')),
9 | customConfig({
10 | output: {
11 | // Created bundle will be a module instead of a stand-alone self-running bundle
12 | // So we can require() it and check if it works
13 | libraryTarget: 'commonjs2'
14 | }
15 | })
16 | ])
17 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/postcss-sass-sourcemaps/styles.sass:
--------------------------------------------------------------------------------
1 | $PADDING: 25px
2 |
3 | body
4 | padding: $PADDING
5 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/postcss-sass-sourcemaps/webpack.config.js:
--------------------------------------------------------------------------------
1 | const { createConfig, entryPoint, setMode, setOutput } = require('../../index')
2 |
3 | const path = require('path')
4 | const { match } = require('@webpack-blocks/webpack')
5 | const { css } = require('@webpack-blocks/assets')
6 | const postcss = require('@webpack-blocks/postcss')
7 | const sass = require('@webpack-blocks/sass')
8 | const postcssVars = require('postcss-simple-vars')
9 |
10 | module.exports = createConfig([
11 | setMode('development'),
12 | entryPoint(path.join(__dirname, 'styles.sass')),
13 | setOutput(path.join(__dirname, 'build/bundle.js')),
14 | match('*.sass', [
15 | css({ sourceMap: true }),
16 | postcss({
17 | plugins: [postcssVars]
18 | }),
19 | sass({ indentSyntax: true, sourceMap: true })
20 | ])
21 | ])
22 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/sass-css-modules/src/index.js:
--------------------------------------------------------------------------------
1 | import { myClass } from './styles.scss'
2 |
3 | export default myClass
4 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/sass-css-modules/src/styles.scss:
--------------------------------------------------------------------------------
1 | $HOVER_COLOR: #ff0000;
2 | $MARGIN: 10px;
3 |
4 | .myClass {
5 | margin: $MARGIN;
6 |
7 | &:hover {
8 | color: $HOVER_COLOR;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/sass-css-modules/webpack.config.js:
--------------------------------------------------------------------------------
1 | const { createConfig, entryPoint, match, setMode, setOutput } = require('../../index')
2 | const { css } = require('@webpack-blocks/assets')
3 | const extractText = require('@webpack-blocks/extract-text')
4 | const sass = require('@webpack-blocks/sass')
5 | const path = require('path')
6 |
7 | module.exports = createConfig([
8 | setMode('development'),
9 | entryPoint(path.join(__dirname, 'src/index.js')),
10 | setOutput(path.join(__dirname, 'build/bundle.js')),
11 | match('*.scss', [css.modules(), sass(), extractText('./styles.css')])
12 | ])
13 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/sass-extract-text/app.js:
--------------------------------------------------------------------------------
1 | require('./styles.sass')
2 |
3 | module.exports = process.env.TEST
4 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/sass-extract-text/styles.sass:
--------------------------------------------------------------------------------
1 | $PADDING: 25px
2 |
3 | body
4 | padding: $PADDING
5 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/sass-extract-text/webpack.config.js:
--------------------------------------------------------------------------------
1 | const { createConfig, entryPoint, match, setMode, setOutput } = require('../../index')
2 |
3 | const path = require('path')
4 | const { css } = require('@webpack-blocks/assets')
5 | const extractText = require('@webpack-blocks/extract-text')
6 | const sass = require('@webpack-blocks/sass')
7 |
8 | module.exports = createConfig([
9 | setMode('development'),
10 | entryPoint(path.join(__dirname, 'app.js')),
11 | setOutput(path.join(__dirname, 'build/bundle.js')),
12 | match('*.sass', [css(), sass({ indentSyntax: true }), extractText('styles.css')])
13 | ])
14 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/typescript/app.ts:
--------------------------------------------------------------------------------
1 | function add(a: number, b: number) {
2 | return a + b
3 | }
4 |
5 | module.exports = process.env.TEST
6 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/typescript/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "noImplicitAny": true,
5 | "removeComments": true,
6 | "preserveConstEnums": true,
7 | "sourceMap": true,
8 | "target": "es2015",
9 | "jsx": "react",
10 | "typeRoots": ["../../../../node_modules/@types"]
11 | },
12 | "compileOnSave": false,
13 | "files": [
14 | "app.ts"
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/typescript/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tslint:latest",
3 | "rules": {
4 | "curly": true,
5 | "semicolon": [true, "never"],
6 | "typedef-whitespace": [
7 | true,
8 | {
9 | "call-signature": "space",
10 | "index-signature": "nospace",
11 | "parameter": "onespace",
12 | "property-declaration": "onespace",
13 | "variable-declaration": "onespace"
14 | },
15 | {
16 | "call-signature": "onespace",
17 | "index-signature": "onespace",
18 | "parameter": "onespace",
19 | "property-declaration": "onespace",
20 | "variable-declaration": "onespace"
21 | }
22 | ]
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/webpack/__e2e-fixtures__/typescript/webpack.config.js:
--------------------------------------------------------------------------------
1 | const {
2 | createConfig,
3 | defineConstants,
4 | entryPoint,
5 | performance,
6 | setDevTool,
7 | setMode,
8 | setOutput
9 | } = require('../../index')
10 |
11 | const typescript = require('@webpack-blocks/typescript')
12 | const tslint = require('@webpack-blocks/tslint')
13 | const path = require('path')
14 |
15 | module.exports = createConfig([
16 | setDevTool(false),
17 | setMode('development'),
18 | entryPoint(path.join(__dirname, 'app.ts')),
19 | setOutput(path.join(__dirname, 'build/bundle.js')),
20 | typescript({ configFileName: path.resolve(__dirname, './tsconfig.json') }),
21 | tslint({
22 | emitErrors: true,
23 | configuration: {
24 | rules: {
25 | 'typedef-whitespace': false
26 | }
27 | }
28 | }),
29 | performance({
30 | maxAssetSize: 100000,
31 | maxEntrypointSize: 500000,
32 | hints: 'error'
33 | }),
34 | defineConstants({
35 | 'process.env.TEST': 'This is the injected process.env.TEST!'
36 | })
37 | ])
38 |
--------------------------------------------------------------------------------
/packages/webpack/__tests__/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parserOptions": {
3 | "ecmaVersion": 8
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/packages/webpack/__tests__/devServer.integration.test.js:
--------------------------------------------------------------------------------
1 | const test = require('ava')
2 | const { createConfig } = require('@webpack-blocks/core')
3 | const devServer = require('@webpack-blocks/dev-server')
4 | const { entryPoint } = require('../index')
5 |
6 | const webpack = {
7 | HotModuleReplacementPlugin: class HotModuleReplacementPlugin {},
8 | NamedModulesPlugin: class NamedModulesPlugin {}
9 | }
10 |
11 | const commonConfig = {
12 | stats: {
13 | children: false,
14 | chunks: false,
15 | modules: false,
16 | reasons: false
17 | },
18 | module: {
19 | rules: []
20 | },
21 | plugins: [new webpack.HotModuleReplacementPlugin()],
22 | resolve: {
23 | extensions: ['.js', '.json']
24 | }
25 | }
26 |
27 | test('devServer() without options provides expected defaults', t => {
28 | const config = createConfig({ webpack }, [
29 | entryPoint({
30 | main: ['./test.js']
31 | }),
32 | devServer()
33 | ])
34 |
35 | t.deepEqual(
36 | config,
37 | Object.assign(commonConfig, {
38 | entry: {
39 | main: ['./test.js']
40 | },
41 | devServer: {
42 | hot: true,
43 | hotOnly: true,
44 | historyApiFallback: true,
45 | inline: true,
46 | clientLogLevel: 'error',
47 | stats: 'errors-only'
48 | }
49 | })
50 | )
51 | t.true(config.plugins[0] instanceof webpack.HotModuleReplacementPlugin)
52 | })
53 |
54 | test('devServer() uses custom options and can be composed', t => {
55 | const config = createConfig({ webpack }, [
56 | entryPoint({
57 | main: ['./test.js'],
58 | second: ['./second.js']
59 | }),
60 | devServer({
61 | inline: false
62 | }),
63 | devServer('some-entry-point')
64 | ])
65 |
66 | t.deepEqual(
67 | config,
68 | Object.assign(commonConfig, {
69 | entry: {
70 | main: ['./test.js', 'some-entry-point'],
71 | second: ['./second.js', 'some-entry-point']
72 | },
73 | devServer: {
74 | hot: true,
75 | hotOnly: true,
76 | historyApiFallback: true,
77 | inline: false,
78 | clientLogLevel: 'error',
79 | stats: 'errors-only'
80 | }
81 | })
82 | )
83 | t.true(config.plugins[0] instanceof webpack.HotModuleReplacementPlugin)
84 | })
85 |
86 | // Regression test for https://github.com/andywer/webpack-blocks/issues/76
87 | test('devServer block extends multiple entry points correctly', t => {
88 | const config = createConfig({ webpack }, [
89 | entryPoint({
90 | a: './a',
91 | b: ['./b']
92 | }),
93 | devServer()
94 | ])
95 |
96 | t.deepEqual(config.entry, {
97 | a: ['./a'],
98 | b: ['./b']
99 | })
100 | })
101 |
--------------------------------------------------------------------------------
/packages/webpack/__tests__/end-to-end.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import fs from 'mz/fs'
3 | import { JSDOM } from 'jsdom'
4 | import path from 'path'
5 | import webpack from 'webpack'
6 |
7 | const fixturesPath = path.join(__dirname, '../__e2e-fixtures__')
8 |
9 | test('building a minimal webpack project works', async t => {
10 | const projectPath = path.join(fixturesPath, 'minimal')
11 | const buildPath = path.join(projectPath, 'build')
12 |
13 | const config = require(path.join(projectPath, 'webpack.config.js'))
14 | await runWebpack(config)
15 |
16 | const bundleExports = require(path.join(buildPath, 'bundle.js'))
17 | t.is(bundleExports, 'I am the minimal test export')
18 | })
19 |
20 | test('building the babel/postcss/extract-text project works', async t => {
21 | const projectPath = path.join(fixturesPath, 'babel-postcss-extract-text')
22 | const buildPath = path.join(projectPath, 'build')
23 |
24 | const config = require(path.join(projectPath, 'webpack.config.js'))
25 | await runWebpack(config)
26 |
27 | require(path.join(buildPath, 'bundle.js'))
28 |
29 | // Check if bundle contains injected process.env.TEST
30 | const bundleContents = await fs.readFile(path.join(buildPath, 'bundle.js'), { encoding: 'utf8' })
31 | t.true(bundleContents.indexOf('module.exports = "This is the injected process.env.TEST!"') > -1)
32 |
33 | // Check if CSS file contains correct content
34 | const styleContents = await fs.readFile(path.join(buildPath, 'styles.css'), { encoding: 'utf8' })
35 | t.true(removeWhitespaces(styleContents).indexOf(removeWhitespaces('.app { margin: 40px; }')) > -1)
36 | })
37 |
38 | test('building the sass/extract-text project works', async t => {
39 | const projectPath = path.join(fixturesPath, 'sass-extract-text')
40 | const buildPath = path.join(projectPath, 'build')
41 |
42 | const config = require(path.join(projectPath, 'webpack.config.js'))
43 | await runWebpack(config)
44 |
45 | global.window = new JSDOM('')
46 | global.document = global.window.document
47 | require(path.join(buildPath, 'bundle.js'))
48 |
49 | // Check if CSS file contains correct content
50 | const styleContents = await fs.readFile(path.join(buildPath, 'styles.css'), { encoding: 'utf8' })
51 | t.true(
52 | removeWhitespaces(styleContents).indexOf(removeWhitespaces('body { padding: 25px; }')) > -1
53 | )
54 | })
55 |
56 | test('building the typescript project works', async t => {
57 | const projectPath = path.join(fixturesPath, 'typescript')
58 | const buildPath = path.join(projectPath, 'build')
59 |
60 | const config = require(path.join(projectPath, 'webpack.config.js'))
61 | await runWebpack(config)
62 |
63 | global.window = new JSDOM('')
64 | global.document = global.window.document
65 | require(path.join(buildPath, 'bundle.js'))
66 |
67 | // Check if bundle contains injected process.env.TEST
68 | const bundleContents = await fs.readFile(path.join(buildPath, 'bundle.js'), { encoding: 'utf8' })
69 | t.true(bundleContents.indexOf('module.exports = "This is the injected process.env.TEST!"') > -1)
70 | })
71 |
72 | test('the postcss/sass/source-maps project build does not fail', async t => {
73 | // Regression test for https://github.com/andywer/webpack-blocks/issues/116
74 |
75 | const projectPath = path.join(fixturesPath, 'postcss-sass-sourcemaps')
76 |
77 | const config = require(path.join(projectPath, 'webpack.config.js'))
78 | await runWebpack(config)
79 |
80 | t.pass()
81 | })
82 |
83 | test('building the sass/css-modules project works', async t => {
84 | const projectPath = path.join(fixturesPath, 'sass-css-modules')
85 | const buildPath = path.join(projectPath, 'build')
86 |
87 | const config = require(path.join(projectPath, 'webpack.config.js'))
88 | await runWebpack(config)
89 |
90 | global.window = new JSDOM('')
91 | global.document = global.window.document
92 | require(path.join(buildPath, 'bundle.js'))
93 |
94 | // Check if CSS file contains correct content
95 | const styleContents = await fs.readFile(path.join(buildPath, 'styles.css'), { encoding: 'utf8' })
96 | t.truthy(removeWhitespaces(styleContents).match(/\.styles--myClass--[0-9a-zA-Z]+{margin:10px;}/))
97 | t.truthy(
98 | removeWhitespaces(styleContents).match(/\.styles--myClass--[0-9a-zA-Z]+:hover{color:#ff0000;}/)
99 | )
100 | })
101 |
102 | function runWebpack(config) {
103 | return new Promise((resolve, reject) => {
104 | webpack(config, (error, stats) => {
105 | if (error) {
106 | reject(error)
107 | } else if (stats.hasErrors()) {
108 | // eslint-disable-next-line no-console
109 | stats.toJson().errors.forEach(error => console.error(error, '\n'))
110 | reject(new Error('Webpack soft error occured. See stderr output.'))
111 | } else {
112 | resolve(stats)
113 | }
114 | })
115 | })
116 | }
117 |
118 | function removeWhitespaces(string) {
119 | return string.replace(/\s/g, '')
120 | }
121 |
--------------------------------------------------------------------------------
/packages/webpack/__tests__/entryPoint.test.js:
--------------------------------------------------------------------------------
1 | const test = require('ava')
2 | const sinon = require('sinon')
3 | const { entryPoint } = require('../index')
4 |
5 | test('entryPoint() should normalize string to object entry', t => {
6 | const merge = sinon.spy(() => prevConfig => prevConfig)
7 |
8 | entryPoint('./test.js')(null, { merge })({})
9 |
10 | t.is(merge.callCount, 1)
11 | t.deepEqual(merge.lastCall.args, [
12 | {
13 | entry: {
14 | main: ['./test.js']
15 | }
16 | }
17 | ])
18 | })
19 |
20 | test('entryPoint() should normalize string array to object entry', t => {
21 | const merge = sinon.spy(() => prevConfig => prevConfig)
22 |
23 | entryPoint(['./test.js', './test2.js'])(null, { merge })({})
24 |
25 | t.is(merge.callCount, 1)
26 | t.deepEqual(merge.lastCall.args, [
27 | {
28 | entry: {
29 | main: ['./test.js', './test2.js']
30 | }
31 | }
32 | ])
33 | })
34 |
35 | test("entryPoint() should normalize an entry object's values", t => {
36 | const merge = sinon.spy(() => prevConfig => prevConfig)
37 |
38 | entryPoint({
39 | main: './app.js',
40 | test: ['./test.js']
41 | })(null, { merge })({})
42 |
43 | t.is(merge.callCount, 1)
44 | t.deepEqual(merge.lastCall.args, [
45 | {
46 | entry: {
47 | main: ['./app.js'],
48 | test: ['./test.js']
49 | }
50 | }
51 | ])
52 | })
53 |
--------------------------------------------------------------------------------
/packages/webpack/__tests__/integration.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import path from 'path'
3 | import {
4 | createConfig,
5 | entryPoint,
6 | match,
7 | setOutput,
8 | sourceMaps,
9 | resolve,
10 | setMode,
11 | optimization
12 | } from '../index'
13 | import { css, file, url } from '@webpack-blocks/assets'
14 | import babel from '@webpack-blocks/babel'
15 | import devServer from '@webpack-blocks/dev-server'
16 | import postcss from '@webpack-blocks/postcss'
17 | import sass from '@webpack-blocks/sass'
18 |
19 | test('complete webpack config creation', t => {
20 | const images = ['*.gif', '*.jpg', '*.jpeg', '*.png', '*.webp']
21 | const fonts = ['*.eot', '*.ttf', '*.woff', '*.woff2']
22 |
23 | const webpackConfig = createConfig([
24 | setMode('development'),
25 | entryPoint('./src/main.js'),
26 | setOutput('./build/bundle.js'),
27 | babel(),
28 | sourceMaps(),
29 | devServer({
30 | proxy: {
31 | '/api/*': { target: 'http://localhost:8080' }
32 | }
33 | }),
34 | match('*.scss', [
35 | css.modules({
36 | modules: {
37 | localIdentName: '[name]--[local]--[hash:base64:5]'
38 | }
39 | }),
40 | postcss(),
41 | sass()
42 | ]),
43 | match(images, { exclude: /node_modules/ }, [
44 | url({
45 | limit: 10000
46 | })
47 | ]),
48 | match(fonts, [file()]),
49 | optimization({
50 | splitChunks: 'all'
51 | })
52 | ])
53 |
54 | t.is(webpackConfig.module.rules.length, 4)
55 | t.deepEqual(webpackConfig.module.rules[0], {
56 | test: /^.*\.scss$/,
57 | use: [
58 | {
59 | loader: 'style-loader',
60 | options: {}
61 | },
62 | {
63 | loader: 'css-loader',
64 | options: {
65 | modules: {
66 | localIdentName: '[name]--[local]--[hash:base64:5]'
67 | },
68 | importLoaders: 1
69 | }
70 | },
71 | {
72 | loader: 'postcss-loader',
73 | options: {}
74 | },
75 | {
76 | loader: 'sass-loader',
77 | options: {}
78 | }
79 | ]
80 | })
81 | t.deepEqual(webpackConfig.module.rules[1], {
82 | test: [/^.*\.gif$/, /^.*\.jpg$/, /^.*\.jpeg$/, /^.*\.png$/, /^.*\.webp$/],
83 | exclude: /node_modules/,
84 | use: [
85 | {
86 | loader: 'url-loader',
87 | options: {
88 | limit: 10000
89 | }
90 | }
91 | ]
92 | })
93 | t.deepEqual(webpackConfig.module.rules[2], {
94 | test: [/^.*\.eot$/, /^.*\.ttf$/, /^.*\.woff$/, /^.*\.woff2$/],
95 | use: [
96 | {
97 | loader: 'file-loader',
98 | options: {}
99 | }
100 | ]
101 | })
102 | t.deepEqual(webpackConfig.module.rules[3], {
103 | test: /\.(js|jsx)$/,
104 | exclude: /node_modules/,
105 | use: [
106 | {
107 | loader: 'babel-loader',
108 | options: {
109 | cacheDirectory: true
110 | }
111 | }
112 | ]
113 | })
114 |
115 | t.is(webpackConfig.mode, 'development')
116 |
117 | t.deepEqual(webpackConfig.entry, { main: ['./src/main.js'] })
118 |
119 | t.deepEqual(webpackConfig.devServer, {
120 | hot: true,
121 | hotOnly: true,
122 | historyApiFallback: true,
123 | inline: true,
124 | clientLogLevel: 'error',
125 | stats: 'errors-only',
126 | proxy: {
127 | '/api/*': { target: 'http://localhost:8080' }
128 | }
129 | })
130 |
131 | t.deepEqual(webpackConfig.output, {
132 | filename: 'bundle.js',
133 | path: path.resolve('./build')
134 | })
135 |
136 | t.is(webpackConfig.devtool, 'cheap-module-eval-source-map')
137 |
138 | t.deepEqual(webpackConfig.optimization, {
139 | splitChunks: 'all'
140 | })
141 |
142 | t.deepEqual(Object.keys(webpackConfig).sort(), [
143 | 'devServer',
144 | 'devtool',
145 | 'entry',
146 | 'mode',
147 | 'module',
148 | 'optimization',
149 | 'output',
150 | 'plugins',
151 | 'resolve',
152 | 'stats'
153 | ])
154 | })
155 |
156 | test('createConfig() creates a minimal configuration', t => {
157 | const webpackConfig = createConfig([entryPoint('./src/main.js'), setOutput('./build/bundle.js')])
158 |
159 | t.deepEqual(webpackConfig, {
160 | entry: {
161 | main: ['./src/main.js']
162 | },
163 | module: {
164 | rules: []
165 | },
166 | output: {
167 | filename: 'bundle.js',
168 | path: path.resolve('./build')
169 | },
170 | stats: {
171 | children: false,
172 | chunks: false,
173 | modules: false,
174 | reasons: false
175 | },
176 | plugins: [],
177 | resolve: {
178 | extensions: ['.js', '.json']
179 | }
180 | })
181 | })
182 |
183 | test('context contains necessary properties', t => {
184 | t.plan(5)
185 |
186 | createConfig([
187 | context => {
188 | // context.webpack
189 | t.is(typeof context.webpack, 'function')
190 | t.is(typeof context.webpack.EnvironmentPlugin, 'function')
191 |
192 | // context.webpackVersion
193 | t.is(typeof context.webpackVersion, 'object')
194 | t.is(typeof context.webpackVersion.major, 'number')
195 | t.is(typeof context.webpackVersion.minor, 'number')
196 |
197 | return prevConfig => prevConfig
198 | }
199 | ])
200 | })
201 |
202 | test('prepends custom extension to default ones', t => {
203 | const expectedExtensionOrder = ['.custom.js', '.js', '.json']
204 |
205 | const webpackConfig = createConfig([resolve({ extensions: ['.custom.js'] })])
206 |
207 | const actualExtensions = webpackConfig.resolve.extensions
208 |
209 | t.deepEqual(actualExtensions, expectedExtensionOrder)
210 | })
211 |
--------------------------------------------------------------------------------
/packages/webpack/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Webpack base config block.
3 | *
4 | * @see https://webpack.github.io/docs/configuration.html
5 | */
6 |
7 | const core = require('@webpack-blocks/core')
8 | const webpack = require('webpack')
9 | const webpackMerge = require('webpack-merge')
10 | const path = require('path')
11 | const parseVersion = require('./lib/parseVersion')
12 |
13 | const webpackVersion = parseVersion(require('webpack/package.json').version)
14 |
15 | exports.env = core.env
16 | exports.group = core.group
17 | exports.match = core.match
18 | exports.when = core.when
19 |
20 | exports.createConfig = createConfig
21 |
22 | exports.setMode = setMode
23 | exports.addPlugins = addPlugins
24 | exports.customConfig = customConfig
25 | exports.defineConstants = require('./lib/defineConstants')
26 | exports.setEnv = require('./lib/setEnv')
27 | exports.entryPoint = entryPoint
28 | exports.performance = performance
29 | exports.optimization = optimization
30 | exports.resolve = resolve
31 | exports.setContext = setContext
32 | exports.setDevTool = setDevTool
33 | exports.setOutput = setOutput
34 | exports.sourceMaps = sourceMaps
35 |
36 | /**
37 | * Takes an array of webpack blocks and creates a webpack config out of them.
38 | * Each webpack block is a callback function which will be invoked to return a
39 | * partial webpack config. These partial configs are merged to create the
40 | * final, complete webpack config that will be returned.
41 | *
42 | * Wraps @webpack-blocks/core's `createConfig`.
43 | *
44 | * @param {Function[]} configSetters Array of functions as returned by webpack blocks.
45 | * @return {object} Webpack config object.
46 | */
47 | function createConfig(configSetters) {
48 | return core.createConfig({ webpack, webpackVersion }, [createEmptyConfig].concat(configSetters))
49 | }
50 |
51 | function createEmptyConfig(context, util) {
52 | return util.merge({
53 | module: {
54 | rules: []
55 | },
56 | plugins: []
57 | })
58 | }
59 |
60 | /**
61 | * @see https://webpack.js.org/concepts/mode
62 | */
63 | function setMode(mode) {
64 | return (context, util) => {
65 | context.mode = mode
66 | return util.merge({ mode })
67 | }
68 | }
69 |
70 | /**
71 | * Adds one or multiple entry points. If the parameter is not an object the
72 | * entry point(s) will be added to the default chunk named `main`.
73 | *
74 | * @param {object|string[]|string} entry
75 | * @see https://webpack.github.io/docs/configuration.html#entry
76 | */
77 | function entryPoint(entry) {
78 | return (context, util) =>
79 | util.merge({
80 | entry: normalizeEntry(entry)
81 | })
82 | }
83 |
84 | function normalizeEntry(entry) {
85 | if (Array.isArray(entry)) {
86 | return {
87 | main: entry
88 | }
89 | } else if (typeof entry === 'string') {
90 | return {
91 | main: [entry]
92 | }
93 | } else if (typeof entry === 'object') {
94 | Object.keys(entry).forEach(entryName => {
95 | if (!Array.isArray(entry[entryName])) {
96 | entry[entryName] = [entry[entryName]]
97 | }
98 | })
99 | return entry
100 | } else {
101 | throw new Error(`Expected entry point to be object, array or string. Instead got: ${entry}`)
102 | }
103 | }
104 |
105 | /**
106 | * @see https://webpack.github.io/docs/configuration.html#plugins
107 | */
108 | function addPlugins(plugins) {
109 | return (context, util) => util.merge({ plugins })
110 | }
111 |
112 | function customConfig(wpConfig) {
113 | return (context, util) => util.merge(wpConfig)
114 | }
115 |
116 | /**
117 | * @param {object} performanceBudget
118 | * @param {number} performanceBudget.maxAssetSize
119 | * @param {number} performanceBudget.maxEntrypointSize
120 | * @param {string} performanceBudget.hints 'warning' or 'error'
121 | */
122 | function performance(performanceBudget) {
123 | return (context, util) =>
124 | util.merge({
125 | performance: performanceBudget
126 | })
127 | }
128 |
129 | /**
130 | * @param {object} optimizationOptions
131 | * @see https://webpack.js.org/configuration/optimization/
132 | */
133 | function optimization(optimizationOptions) {
134 | return (context, util) =>
135 | util.merge({
136 | optimization: optimizationOptions
137 | })
138 | }
139 |
140 | /**
141 | * @see https://webpack.js.org/configuration/resolve/
142 | */
143 | function resolve(config) {
144 | const strategy = { 'resolve.extensions': 'prepend' }
145 | const merge = webpackMerge.smartStrategy(strategy)
146 |
147 | return () => prevConfig =>
148 | merge(prevConfig, {
149 | resolve: config
150 | })
151 | }
152 |
153 | /**
154 | * @see https://webpack.github.io/docs/configuration.html#context
155 | */
156 | function setContext(contextPath) {
157 | return (context, util) =>
158 | util.merge({
159 | context: path.resolve(contextPath)
160 | })
161 | }
162 |
163 | /**
164 | * @see https://webpack.github.io/docs/configuration.html#devtool
165 | */
166 | function setDevTool(devtool) {
167 | return (context, util) => util.merge({ devtool })
168 | }
169 |
170 | /**
171 | * @see https://webpack.github.io/docs/configuration.html#output
172 | */
173 | function setOutput(output) {
174 | if (typeof output === 'string') {
175 | output = {
176 | filename: path.basename(output) || 'bundle.js',
177 | path: path.resolve(path.dirname(output) || './build')
178 | }
179 | }
180 |
181 | return (context, util) => util.merge({ output })
182 | }
183 |
184 | /**
185 | * Just a convenience wrapper to enable sourcemaps in an easier-to-read fashion
186 | * than `setDevTool()`.
187 | * @TODO: Only sets the javascript sourcemaps now. Would be nice to make loaders
188 | * enable their specific sourcemaps when `sourceMaps()` is used.
189 | *
190 | * @param {string} [devtool]
191 | * @return {Function}
192 | */
193 | function sourceMaps(devtool = 'cheap-module-eval-source-map') {
194 | return (context, util) => {
195 | context.sourceMaps = true
196 |
197 | return util.merge({ devtool })
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/packages/webpack/lib/__tests__/defineConstants.test.js:
--------------------------------------------------------------------------------
1 | const test = require('ava')
2 | const { createConfig } = require('@webpack-blocks/core')
3 | const defineConstants = require('../defineConstants')
4 |
5 | const webpack = {
6 | DefinePlugin: function DefinePluginMock(definitions) {
7 | this.definitions = definitions
8 | }
9 | }
10 |
11 | test('defineConstants() creates a single DefinePlugin instance only', t => {
12 | const config = createConfig({ webpack }, [
13 | defineConstants({ a: 'a' }),
14 | defineConstants({ b: 'b' })
15 | ])
16 |
17 | t.is(Object.keys(config.plugins).length, 1)
18 | t.deepEqual(Object.keys(config.plugins[0].definitions), ['a', 'b'])
19 | })
20 |
21 | test('defineConstants() encodes the values', t => {
22 | const config = createConfig({ webpack }, [
23 | defineConstants({
24 | foo: 'foo',
25 | bar: {
26 | baz: 3
27 | }
28 | })
29 | ])
30 |
31 | t.is(Object.keys(config.plugins).length, 1)
32 | t.deepEqual(config.plugins[0].definitions, {
33 | foo: '"foo"',
34 | bar: '{\n "baz": 3\n}'
35 | })
36 | })
37 |
--------------------------------------------------------------------------------
/packages/webpack/lib/__tests__/parseVersion.test.js:
--------------------------------------------------------------------------------
1 | const test = require('ava')
2 | const parseVersion = require('../parseVersion')
3 |
4 | test('parseVersion() works', t => {
5 | t.deepEqual(parseVersion('1.2.3'), {
6 | major: 1,
7 | minor: 2,
8 | patch: 3,
9 | prerelease: '',
10 | raw: '1.2.3'
11 | })
12 |
13 | t.deepEqual(parseVersion('0.12.0-beta'), {
14 | major: 0,
15 | minor: 12,
16 | patch: 0,
17 | prerelease: 'beta',
18 | raw: '0.12.0-beta'
19 | })
20 |
21 | t.deepEqual(parseVersion('2.2.0-rc.1'), {
22 | major: 2,
23 | minor: 2,
24 | patch: 0,
25 | prerelease: 'rc.1',
26 | raw: '2.2.0-rc.1'
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/packages/webpack/lib/__tests__/setEnv.test.js:
--------------------------------------------------------------------------------
1 | const test = require('ava')
2 | const { createConfig } = require('@webpack-blocks/core')
3 | const setEnv = require('../setEnv')
4 |
5 | const webpack = {
6 | EnvironmentPlugin: function EnvironmentPluginMock(definitions) {
7 | this.definitions = definitions
8 | }
9 | }
10 |
11 | test('setEnv() creates a single EnvironmentPlugin instance only', t => {
12 | const config = createConfig({ webpack }, [setEnv(['a']), setEnv({ b: 'foo' })])
13 |
14 | t.is(Object.keys(config.plugins).length, 1)
15 | t.deepEqual(config.plugins[0].definitions, { a: undefined, b: 'foo' })
16 | })
17 |
--------------------------------------------------------------------------------
/packages/webpack/lib/defineConstants.js:
--------------------------------------------------------------------------------
1 | module.exports = defineConstants
2 |
3 | /**
4 | * Replaces constants in your source code with a value (`process.env.NODE_ENV`
5 | * for example) using the `webpack.DefinePlugin`. Every constant's value is
6 | * `JSON.stringify()`-ed first, so you don't have to remember.
7 | *
8 | * Using `defineConstants` multiple times results in a single
9 | * DefinePlugin instance configured to do all the replacements.
10 | *
11 | * @param {object} constants { [constantName: string]: * }
12 | * @return {Function}
13 | */
14 | function defineConstants(constants) {
15 | const setter = context => prevConfig => {
16 | context.defineConstants = Object.assign({}, context.defineConstants, constants)
17 | return prevConfig
18 | }
19 |
20 | return Object.assign(setter, { post: addDefinePlugin })
21 | }
22 |
23 | function addDefinePlugin(context, util) {
24 | const stringify = value => JSON.stringify(value, null, 2)
25 | const stringifiedConstants = mapProps(context.defineConstants, stringify)
26 |
27 | return util.addPlugin(new context.webpack.DefinePlugin(stringifiedConstants))
28 | }
29 |
30 | function mapProps(object, valueMapper) {
31 | return Object.keys(object)
32 | .map(propKey => ({ [propKey]: valueMapper(object[propKey]) }))
33 | .reduce((newObject, partial) => Object.assign(newObject, partial), {})
34 | }
35 |
--------------------------------------------------------------------------------
/packages/webpack/lib/parseVersion.js:
--------------------------------------------------------------------------------
1 | module.exports = parseVersion
2 |
3 | /**
4 | * Parse semver-compliant version string.
5 | *
6 | * @param {string} versionString
7 | * @return {object} { major: number, minor: number, patch: number, prerelease: string, raw: string }
8 | */
9 | function parseVersion(versionString) {
10 | const [release, prerelease] = versionString.split('-')
11 | const splitRelease = release.split('.').map(number => parseInt(number, 10))
12 |
13 | return {
14 | major: splitRelease[0],
15 | minor: splitRelease[1],
16 | patch: splitRelease[2],
17 | prerelease: prerelease || '',
18 | raw: versionString
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packages/webpack/lib/setEnv.js:
--------------------------------------------------------------------------------
1 | module.exports = setEnv
2 |
3 | /**
4 | * Replaces constants in your source code with values from `process.env`
5 | * using the `webpack.EnvironmentPlugin`.
6 | *
7 | * Using `setEnv` multiple times results in a single
8 | * EnvironmentPlugin instance configured to do all the replacements.
9 | *
10 | * @param {string[]|object} constants
11 | * @return {Function}
12 | */
13 | function setEnv(constants) {
14 | const setter = context => prevConfig => {
15 | context.setEnv = Object.assign({}, context.setEnv, toObject(constants))
16 | return prevConfig
17 | }
18 |
19 | return Object.assign(setter, { post: addEnvironmentPlugin })
20 | }
21 |
22 | function addEnvironmentPlugin(context, util) {
23 | return util.addPlugin(new context.webpack.EnvironmentPlugin(context.setEnv))
24 | }
25 |
26 | function toObject(constants) {
27 | if (Array.isArray(constants)) {
28 | return constants.reduce((result, constant) => {
29 | // Setting the default (fallback) value to `undefined`
30 | // to make sure the EnvironmentPlugin will throw a warning
31 | // in case if `process.env[constant]` was not defined too.
32 | result[constant] = undefined
33 | return result
34 | }, {})
35 | }
36 |
37 | return constants
38 | }
39 |
--------------------------------------------------------------------------------
/packages/webpack/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@webpack-blocks/webpack",
3 | "version": "2.1.0",
4 | "description": "Webpack block for the webpack 2.x base configuration.",
5 | "license": "MIT",
6 | "author": "Andy Wermke ",
7 | "engines": {
8 | "node": ">= 6.0"
9 | },
10 | "keywords": [
11 | "webpack",
12 | "webpack-blocks"
13 | ],
14 | "repository": "andywer/webpack-blocks",
15 | "bugs": "https://github.com/andywer/webpack-blocks/issues",
16 | "dependencies": {
17 | "@webpack-blocks/core": "^2.1.0",
18 | "webpack-merge": "^4.2.2"
19 | },
20 | "devDependencies": {
21 | "@types/node": "^10.11.6",
22 | "@webpack-blocks/assets": "^2.1.0",
23 | "@webpack-blocks/babel": "^2.1.0",
24 | "@webpack-blocks/dev-server": "^2.1.0",
25 | "@webpack-blocks/extract-text": "^2.1.0",
26 | "@webpack-blocks/postcss": "^2.1.0",
27 | "@webpack-blocks/sass": "^2.1.0",
28 | "@webpack-blocks/tslint": "^2.0.1",
29 | "@webpack-blocks/typescript": "^2.0.1",
30 | "awesome-typescript-loader": "^5.2.1",
31 | "babel-loader": "^8.0.4",
32 | "css-loader": "^1.0.0",
33 | "extract-text-webpack-plugin": "^4.0.0-beta.0",
34 | "jsdom": "^16.5.0",
35 | "mz": "^2.7.0",
36 | "node-sass": "^4.12.0",
37 | "postcss-loader": "^3.0.0",
38 | "postcss-simple-vars": "^5.0.1",
39 | "sass-loader": "^7.1.0",
40 | "sinon": "^6.3.5",
41 | "style-loader": "^0.23.1",
42 | "tslint": "^5.11.0",
43 | "tslint-loader": "^3.6.0",
44 | "typescript": "^3.1.2",
45 | "webpack": "^4.20.2"
46 | },
47 | "peerDependencies": {
48 | "webpack": "^4.0.0"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------