1,修改配置文件:
module: {
rules: [
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
}
]
}
2,在项目中添加一些字体文件
// style.less
// 使用 css3 的 font-face 定义字体
@font-face {
font-family: iconfont; // 我们定义的字体的名字
src: url('./fonts/iconfont.ttf') format('truetype'); // 加载资源 format格式
}
// 在项目中使用这个字体文件
// 定义一个 icon 类
.icon {
font-family: 'iconfont';
font-size: 30px;
color: pink;
}
// 然后就可以在页面里使用了
4, 使用字体
const span = document.createElement('span')
span.classList.add('icon')
span.innerHTML = ''
document.body.appendChild(span)
执行编译npx webpack-dev-server
此外,可以加载的有用资源还有数据,如 JSON 文件,CSV、TSV 和 XML。类似于 NodeJS,JSON 支持实际上是内置的,也就是说
默认将正常运行。要导入 CSV、TSV 和 XML,我们可以使用 csv-loader 和 xml-loader
首先安装:
npm install --save-dev csv-loader xml-loader
添加配置文件:
module: {
rules: [
{
test: /\.(csv|tsv)$/i,
use: ['csv-loader'],
}, {
test: /\.xml$/i,
use: ['xml-loader'],
}
]
}
// data.xml
xiaowang
Jerry
heading
Hello, webpack ~
// data.csv
触发频率不稳定,受很多因素影响。比如当我们的浏览器切换tab后,之前tab注册的requestIdleCallback触发的频率会变得很低
基于以上原因,React实现了功能更完备的requestIdleCallbackpolyfill,这就是Scheduler。除了在空闲时触发回调的功能外,Scheduler还提供了多种调度优先级供任务设置。
入口文件里加载数据模块,并在控制台上打印导出内容
// index.js
import DataXml from './data.xml'
import DataCsv from './data.csv'
console.log(DataXml)
console.log(DataCsv)
通过使用自定义 parser 替代特定的 webpack loader,可以将任何 toml 、 yaml 或 json5 文件作为 JSON 模块导入
在src下创建文件:data.toml 、data.yaml、data.json5
// data.toml
title = 'TOML'
[owner]
name = 'xiaowang'
age = 18
// data.yaml
title: 'Yaml'
owner:
name: 'xiaowang'
age: 18
// data.json5
{
title: 'JSON5',
owner: {
name: 'xiaowang',
age: 18
}
}
首先安装 toml、yamljs 和 json5 的 packages:
npm install toml yamljs json5 --save-dev
并配置webpack.config.js
const toml = require('toml')
const yaml = require('yamljs')
const json5 = require('json5')
rules: [
{
test: /\.toml$/i,
type: 'json',
parser: {
parse: toml.parse,
},
},
{
test: /\.yaml$/i,
type: 'json',
parser: {
parse: yaml.parse,
},
},
{
test: /\.json5$/i,
type: 'json',
parser: {
parse: json5.parse,
},
}
]
在主文件中引入模块,并打印:
// index.js
import toml from './data.toml'
import yaml from './data.yaml'
import json5 from './data.json5'
console.log(toml)
console.log(yaml)
console.log(json5)
应用 less-loader 编译过 less 文件,应用 xml-loader 编译过 xml 文件,那 js 文件需要编译吗
// 新建test.js
function getString() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello world~')
}, 2000)
})
}
async function helloWorld() {
let string = await getString()
console.log('test.js =====>', string)
}
// 导出函数模块
export default helloWorld
// index.js
import testHelloWorld from './test'
testHelloWorld()
npx webpack执行编译,启动服务: npx webpack serve
浏览器会 2s 后输出test.js =====> Hello world~, 但是如果浏览器版本过低,就很难保证代码正常运行了
webpack 自身可以自动加载JS文件,就像加载JSON文件一样,无需任何 loader。可是,加载的JS文件会原样输出,即使JS文件里包含ES6+的代码,也不会做任何的转化。那么我们就需要Babel帮忙了,Babel 是一个 JavaScript 编译器,可以将 ES6+ 转化成 ES5。在Webpack里使用Babel,需要使用 babel-loader
npm install -D babel-loader @babel/core @babel/preset-env
在 webpack 配置中,需要将 babel-loader 添加到 module 列表中:
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
编译后可以看出,async/await 的 ES6 语法被 babel 编译了。
此时执行编译,在浏览器里打开项目发现报了一个错误:
regeneratorRuntime 是webpack打包生成的全局辅助函数,由babel生成,用于兼 容async/await的语法
# 这个包中包含了regeneratorRuntime,运行时需要
npm install --save @babel/runtime
# 这个插件会在需要regeneratorRuntime的地方自动require导包,编译时需要
npm install --save-dev @babel/plugin-transform-runtime
# 更多参考这里 https://babeljs.io/docs/en/babel-plugin-transform-runtime
修改配置文件:
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [['@babel/plugin-transform-runtime']]
}
}
}
]
npx webpack-dev-server启动服务:
代码分离是 webpack 中最引人注目的特性之一。此特性能够把代码分离到不同的 bundle 中,然后可以按需加载或并行加载这些文件。代码分离可以用于获取更小的 bundle,以及控制资源加载优先级,如果使用合理,会极大影响加载时间
常用的代码分离方法有三种:
这是迄今为止最简单直观的分离代码的方式。不过,这种方式手动配置较多,并有一些隐患,我们将会解决这些问题。先来看看如何从 main bundle 中分离 another module(另一个模块):
// 新建another-module.js文件
import _ from 'lodash';
console.log(_.join(['apple', 'orange', 'banana']))
// 安装 lodash
npm install lodash --save-dev
修改配置文件:
entry: { // 入口
index: './src/index.js',
another: './src/another-module.js'
},
output: { // 出口
filename: '[name].bundle.js', // 文件名
// ...
},
npx webpack, npx webpack-dev-server:
// 再修改下 index.js
import _ from 'lodash'
console.log('index.js===>', _.join(['index', 'module'], ''))
执行编译npx webpack后,我们可以发现index.bundle.js文件变大了,这种方式存在一些隐患:
以上两点中,第一点对我们的示例来说无疑是个问题,因为之前我们在
./src/index.js 中也引入过 lodash ,这样就在两个 bundle 中造成重复引用
入口依赖
配置 dependOn option 选项,这样可以在多个 chunk 之间共享模块:
entry: {
index: {
imports: './src/index.js',
dependOn: 'shared'
},
another: {
import: './src/another-module.js',
dependOn: 'shared'
},
shared: 'lodash'
},
执行编译npx webpack发现:
index.bundle.js 与 another.bundle.js 共享的模块 lodash.js 被打包到一 个单独的文件 shared.bundle.js 中
SplitChunksPlugin 插件可以将公共的依赖模块提取到已有的入口 chunk 中,或者提取到一个新生成的 chunk。让我们使用这个插件,将之前的示例中重复的 lodash 模块去除:
entry: {
// ....
},
optimization: {
splitChunks: {
chunks: 'all'
}
}
执行编译npx webpack可以看出:
使用 optimization.splitChunks 配置选项后,index.bundle.js 和 another.bundle.js 中已经移除了重复的依赖模块。需要注意的是,插件将 lodash 分离到单独的 chunk,并且将其从 main bundle 中移除,减轻了大小
涉及到动态代码拆分时,webpack 提供了两个类似的技术。第一种使用符合 ECMAScript 提案的 import() 语法来实现动态导入(推荐使用)。第二种,是 webpack 的遗留功能,使用 webpack 特定的 require.ensure
// 第一种
// 创建 async-module.js 文件:
function getComponent() {
return import('lodash')
.then(({
default: _
}) => {
const element = document.createElement('div')
element.innerHTML = _.join(['async', 'module'], '')
return element
})
.catch((error) => 'error')
}
getComponent().then((component) => {
document.body.appendChild(component)
})
// 在入口文件导入:
import './async-module'
执行编译npx webpack后可以看出,除了公共的 lodash 代码被单独打包到一个文件外,还生成了一个vendors-node_modules_babel_runtime_regenerator_index_js-node_modules_babel_runtime_helpers_es-58772e.bundle.js文件。
懒加载或者按需加载,是一种很好的优化网页或应用的方式。这种方式实际上是先把
我们的代码在一些逻辑断点处分离开,然后在一些代码块中完成某些操作后,立即引用
或即将引用另外一些新的代码块。这样加快了应用的初始加载速度,减轻了它的总体
体积,因为某些代码块可能永远不会被加载。
// 创建一个 math.js 文件,在主页面中通过点击按钮调用其中的函数:
export const add = (x, y) => {
return x + y
}
export const minus = (x, y) => {
return x - y
}
// index.js
const button = document.createElement('button') button.textContent = '点击执行加法运算' button.addEventListener('click', () => {
import(/* webpackChunkName: 'math' */ './math.js').then(({ add
}) => {
console.log(add(4, 5))
})
})
document.body.appendChild(button)
// 以上代码中的注释称为 webpack 魔法注释: webpackChunkName: 'math' , 告诉webpack打包生成的文件名为 math
启动服务,我们可以看到第一次加载完页面,math.bundle.js 不会加载,当点击按钮后,才加载 math.bundle.js 文件
Webpack v4.6.0+ 增加了对预获取和预加载的支持。
在声明 import 时,使用下面这些内置指令,可以让 webpack 输出 “resource hint(资源提示)”,来告知浏览器:
下面这个 prefetch 的简单示例中,编辑 index.js 文件:
const button = document.createElement('button') button.textContent = '点击执行加法运算' button.addEventListener('click', () => {
import(/* webpackChunkName: 'math', webpackPrefetch: true */
'./math.js').then(({ add }) => {
console.log(add(4, 5))
})
})
document.body.appendChild(button)
// 添加第二句魔法注释:webpackPrefetch: true
告诉 webpack 执行预获取。这会生成
并追加到页面头部,指示着浏览器在闲置时间预取 math.js 文件
npx webpack-dev-server:
会发现,在还没有点击按钮时, math.bundle.js 就已经下载下来了。同时,在 index.html 里webpack自动添加了一句:
点击按钮,会立即调用已经下载好的math.bundle.js文件中的add方法
与 prefetch 指令相比,preload 指令有许多不同之处:
// 创建一个 print.js 文件:
export const print = () => {
console.log('preload chunk.')
}
// index.js
const button2 = document.createElement('button')
button2.textContent = '点击执行字符串打印'
button2.addEventListener('click', () => {
import(/* webpackChunkName: 'print', webpackPreload: true */
'./print.js').then(({ print }) => {
print(40, 50)
})
})
document.body.appendChild(button2)
启动服务,会发现print.bundle.js 未被下载,因为我们配置的是
webpackPreload , 是在父 chunk 加载时,以并行方式开始加载。点击按钮才加载的
模块不会事先加载的。
再修改下:
// index.js
import(/* webpackChunkName: 'print', webpackPrefetch: true */
'./print.js').then(({ print }) => {
print(40, 50)
})
// 推荐使用webpackPrefetch预获取,print.bundle.js会在网络空闲的时候把将来使用的代码加载出来,这样既不影响首屏的加载速度,又省去了将来模块加载的延迟。
也可以使用webpackPreload实现页面模块的并行下载
print.bundle.js 被加载下来,是和当前 index.bundle.js 并行加载的。
以上,我们使用 webpack 来打包我们的模块化后的应用程序,webpack 会生成一个可部署的 /dist 目录,然后把打包后的内容放置在此目录中。只要 /dist 目录中的内容部署到 server 上,client(通常是浏览器)就能够访问此 server 的网站及其资源。而最后一步获取资源是比较耗费时间的,这就是为什么浏览器使用一种名为缓存的技术。可以通过命中缓存,以降低网络流量,使网站加载速度更快,然而,如果我们在部署新版本时不更改资源的文件名,浏览器可能会认为它没有被更新,就会使用它的缓存版本。由于缓存的存在,当你需要获取新的代码时,就会显得很棘手。
本节通过必要的配置,以确保 webpack 编译生成的文件能够被客户端缓存,而在文件内容变化后,能够请求到新的文件。
我们可以通过替换 output.filename 中的 substitutions 设置,来定义输出文件的 名称。webpack 提供了一种使用称为 substitution(可替换模板字符串) 的方式,通过带括号字符串来模板化文件名。其中, [contenthash] substitution 将根据资源内容创建出唯一hash。当资源内容发生变化时, [contenthash] 也会发生变化。
// 修改配置文件
module.exports = {
output: {
filename: '[name].[contenthash].js',
},
};
可以看到bundle 的名称是它内容(通过 hash)的映射。如果我们不做修改,然后再次运行构建,文件名会保持不变
将第三方库(library)(例如 lodash )提取到单独的 vendor chunk 文件中,是比较推荐的做法,因为它们很少像本地的源代码那样频繁修改。因此通过实现以上步骤,利用 client 的长效缓存机制,命中缓存来消除请求,并减少向 server 获取资源,同时还能保证 client 代码和 server 代码版本一致。 我们在
optimization.splitChunks 添加如下 cacheGroups 参数并构建:
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
npx webpack
目前,全部 js 文件都在 dist 文件夹根目录下,我们尝试把它们放到一个文件夹中,
这个其实也简单,修改配置文件:
output: { // 出口
filename: 'scripts/[name].[contenthash].js'
},
现在,我们只能手工的来调整 mode 选项,实现生产环境和开发环境的切换,且很多配置在生产环境和开发环境中存在不一致的情况,比如开发环境没有必要设置缓存,生产环境还需要设置公共路径等等
接下来我们看怎么拆分开发和生产环境,让打包更灵活
publicPath 配置选项在各种场景中都非常有用。你可以通过它来指定应用程序中所
有资源的基础路径。
// 尝试使用环境变量,否则使用根路径
const ASSET_PATH = process.env.ASSET_PATH || '/'
output: { // 出口
publicPath: ASSET_PATH,
},
plugins: [ // 可以配置多个插件
// 这可以帮助我们在代码中安全地使用环境变量
new webpack.DefinePlugin({
'process.env.ASSET_PATH': JSON.stringify(ASSET_PATH)
})
],
output: { // 出口
publicPath: 'auto',
},
请注意在某些情况下不支持 document.currentScript ,例如:IE 浏览器,我们不得不引入一个 polyfill,例如 currentScript Polyfill
想要消除 webpack.config.js 在开发环境和生产环境之间的差异,我们可能需要
环境变量(environment variable)
webpack 命令行环境配置的 --env 参数,可以允许我们传入任意数量的环境变量。而在 webpack.config.js 中可以访问到这些环境变量。例如,–env production 或
–env goal=local
npx webpack --env goal=local --env production --progress
对于我们的 webpack 配置,有一个必须要修改之处。通常,module.exports 指向配置对象。要使用 env 变量,你必须将 module.exports 转换成一个函数:
module.exports = (env) => {
return {
// 根据命令行参数 env 来设置不同环境的 mode
mode: env.production ? 'production' : 'development', //...
}
}
目前,生产环境和开发环境使用的是一个配置文件,我们需要将这两个文件单独放到不同的配置文件中。如 webpack.config.dev.js (开发环境配置)和
webpack.config.prod.js (生产环境配置)。在项目根目录下创建一个配置文件夹 config 来存放他们。
webpack.config.dev.js 配置如下:
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const toml = require('toml')
const yaml = require('yaml')
const json5 = require('json5')
module.exports = {
entry: {
index: './src/index.js',
another: './src/another-module.js'
},
output: {
filename: 'scripts/[name].js',
path: path.resolve(__dirname, '../dist'), // src目录下
clean: true,
assetModuleFilename: 'images/[contenthash][ext]'
},
mode: 'development',
devtool: 'inline-source-map',
plugins: [
new HtmlWebpackPlugin({
template: './index.html',
filename: 'app.html',
inject: 'body'
}),
new MiniCssExtractPlugin({
filename: 'styles/[contenthash].css'
})],
devServer: {
static: './dist'
},
module: {
rules: [
{
test: /\.png$/,
type: 'asset/resource',
generator: {
filename: 'images/[contenthash][ext]'
}
}, {
test: /\.svg$/,
type: 'asset/inline'
},
{
test: /\.txt$/,
type: 'asset/source'
}, {
test: /\.jpg$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 4 * 1024 * 1024
}
}
},
{
test: /\.(css|less)$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource'
}, {
test: /\.(csv|tsv)$/,
use: 'csv-loader'
},
{
test: /\.xml$/,
use: 'xml-loader'
}, {
test: /\.toml$/,
type: 'json',
parser: {
parse: toml.parse
}
}, {
test: /\.yaml$/,
type: 'json',
parser: {
parse: yaml.parse
}
}, {
test: /\.json5$/,
type: 'json',
parser: {
parse: json5.parse
}
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [
[
]]
}
}
}]
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
}
webpack.config.prod.js配置如下:
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const toml = require('toml')
const yaml = require('yaml')
const json5 = require('json5')
module.exports = {
entry: {
index: './src/index.js',
another: './src/another-module.js'
},
output: {
filename: 'scripts/[name].[contenthash].js',
// 打包的dist文件夹要放到上一层目录
path: path.resolve(__dirname, '../dist'),
clean: true,
assetModuleFilename: 'images/[contenthash][ext]', publicPath: 'http://localhost:8080/'
},
mode: 'production',
plugins: [
new HtmlWebpackPlugin({
template: './index.html',
filename: 'app.html',
inject: 'body'
}),
new MiniCssExtractPlugin({
filename: 'styles/[contenthash].css'
})],
module: {
rules: [
{
test: /\.png$/,
type: 'asset/resource',
generator: {
filename: 'images/[contenthash][ext]'
}
}, {
test: /\.svg$/,
type: 'asset/inline'
},
{
test: /\.txt$/,
type: 'asset/source'
}, {
test: /\.jpg$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 4 * 1024 * 1024
}
}
}, {
test: /\.(css|less)$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
}, {
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource'
},
{
test: /\.(csv|tsv)$/,
use: 'csv-loader'
}, {
test: /\.xml$/,
use: 'xml-loader'
},
{
test: /\.toml$/,
type: 'json',
parser: {
parse: toml.parse
}
}, {
test: /\.yaml$/,
type: 'json',
parser: {
parse: yaml.parse
}
}, {
test: /\.json5$/,
type: 'json',
parser: {
parse: json5.parse
}
}, {
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [
[
]]
}
}
}]
},
optimization: {
minimizer: [
new CssMinimizerPlugin()
],
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
},
//关闭 webpack 的性能提示 performance: { hints:false}
}
拆分成两个配置文件后,分别运行这两个文件:
开发环境:
npx webpack serve -c ./config/webpack.config.dev.js // -c --config的简写
生产环境:
npx webpack serve -c ./config/webpack.config.prod.js
我们也可以启动不同环境的服务:
// 开发环境:
npx webpack serve -c ./config/webpack.config.dev.js
// 生产环境
npx webpack serve -c ./config/webpack.config.prod.js
每次打包或启动服务时,都需要在命令行里输入一长串的命令,我们可以在package.json里配置npm脚本来简化命令行的输入:
// package.json
{
"scripts": {
"start": "webpack serve -c ./config/webpack.config.dev.js",
"build": "webpack -c ./config/webpack.config.prod.js"
}
}
开发环境运行脚本:
npm run start
npm run build
这时,我们发现这两个配置文件里存在大量的重复代码,可以手动的将这些重复的代
码单独提取到一个文件里,
创建 webpack.config.common.js ,配置公共的内容:
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const toml = require('toml')
const yaml = require('yaml')
const json5 = require('json5')
module.exports = {
entry: {
index: './src/index.js',
another: './src/another-module.js'
},
output: {
// 注意这个dist的路径设置成上一级
path: path.resolve(__dirname, '../dist'),
clean: true,
assetModuleFilename: 'images/[contenthash][ext]',
},
plugins: [new HtmlWebpackPlugin({
template: './index.html',
filename: 'app.html',
inject: 'body'
}),
new MiniCssExtractPlugin({
filename: 'styles/[contenthash].css'
})],
module: {
rules: [
{
test: /\.png$/,
type: 'asset/resource',
generator: {
filename: 'images/[contenthash][ext]'
}
}, {
test: /\.svg$/,
type: 'asset/inline'
},
{
test: /\.txt$/,
type: 'asset/source'
}, {
test: /\.jpg$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 4 * 1024
}
}
}, {
test: /\.(css|less)$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
}, {
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource'
},
{
test: /\.(csv|tsv)$/,
use: 'csv-loader'
}, {
test: /\.xml$/,
use: 'xml-loader'
},
{
test: /\.toml$/,
type: 'json',
parser: {
parse: toml.parse
}
}, {
test: /\.yaml$/,
type: 'json',
parser: {
parse: yaml.parse
}
}, {
test: /\.json5$/,
type: 'json',
parser: {
parse: json5.parse
}
}, {
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [
[
]]
}
}
}]
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
},
//关闭 webpack 的性能提示 performance: { hints:false}
}
改写 webpack.config.dev.js :
module.exports = {
// 开发环境不需要配置缓存
output: {
filename: 'scripts/[name].js',
},
// 开发模式
mode: 'development',// 配置 source-map
devtool: 'inline-source-map',
// 本地服务配置 devServer: { static: './dist' }
}
改写webpack.config.prod.js
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
// 生产环境需要缓存
output: {
filename: 'scripts/[name].[contenthash].js', publicPath: 'http://localhost:8080/'
},
// 生产环境模式
mode: 'production',
// 生产环境 css 压缩
optimization: {
minimizer: [
new CssMinimizerPlugin()
]
}
}
配置文件拆分好后,新的问题来了,如何保证配置合并没用问题呢?webpack-merge 这个工具可以完美解决这个问题。
安装 webpack-merge :
npm install webpack-merge -D // --save-dev: -D
创建webpack.config.js,合并代码:
const { merge } = require('webpack-merge')
const commonConfig = require('./webpack.config.common.js')
const productionConfig = require('./webpack.config.prod.js')
const developmentConfig = require('./webpack.config.dev')
module.exports = (env) => {
switch (true) {
case env.development:
return merge(commonConfig, developmentConfig)
case env.production:
return merge(commonConfig, productionConfig)
default:
throw new Error('No matching configuration was found!');
}
}