Production bundle optimizations

Fixed production check in webpack config, removed moment locales and reduced lodash and fontawesome inclusion
This commit is contained in:
Mark van Renswoude 2018-04-29 22:33:27 +02:00
parent 0ebca23587
commit 4db1b2f23d
16 changed files with 232 additions and 131 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@ node_modules
data data
custom/*.js custom/*.js
public/dist/*.js public/dist/*.js
public/dist/*.map
public/dist/index.html public/dist/index.html
config.js config.js
*.sublime-workspace *.sublime-workspace

View File

@ -4,7 +4,6 @@ const config = require('./config');
const Repository = require('./lib/repository'); const Repository = require('./lib/repository');
const NotificationWorker = require('./lib/workers/notification'); const NotificationWorker = require('./lib/workers/notification');
const _ = require('lodash');
const fs = require('fs'); const fs = require('fs');
const express = require('express'); const express = require('express');
const bodyParser = require('body-parser'); const bodyParser = require('body-parser');
@ -17,7 +16,7 @@ const cookieParser = require('cookie-parser');
const webpack = require('webpack'); const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware'); const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware'); const webpackHotMiddleware = require('webpack-hot-middleware');
const webpackConfig = require('./webpack.config.js'); const webpackConfigFactory = require('./webpack.config.js');
(async () => (async () =>
{ {
@ -52,6 +51,7 @@ const webpackConfig = require('./webpack.config.js');
// Frontend // Frontend
if (isDevelopment) if (isDevelopment)
{ {
const webpackConfig = webpackConfigFactory(process.env, { mode: 'development' });
const compiler = webpack(webpackConfig); const compiler = webpack(webpackConfig);
app.use(webpackDevMiddleware(compiler, { app.use(webpackDevMiddleware(compiler, {

View File

@ -1,4 +1,4 @@
const _ = require('lodash'); const map = require('lodash/map');
const retry = require('async-retry'); const retry = require('async-retry');
const generate = require('nanoid/generate'); const generate = require('nanoid/generate');
const markdown = require('markdown').markdown; const markdown = require('markdown').markdown;
@ -137,7 +137,7 @@ class CodeRepository
return; return;
} }
resolve(_.map(docs, (doc) => new Code(doc))); resolve(map(docs, (doc) => new Code(doc)));
}); });
}); });
} }

View File

@ -1,5 +1,3 @@
//const debug = require('debug')('recv:users');
const _ = require('lodash');
const path = require('path'); const path = require('path');
const mkdirp = require('mkdirp'); const mkdirp = require('mkdirp');
const Datastore = require('nedb'); const Datastore = require('nedb');

View File

@ -1,4 +1,4 @@
const _ = require('lodash'); const map = require('lodash/map');
class Notification class Notification
@ -38,7 +38,7 @@ class NotificationRepository
return; return;
} }
resolve(_.map(docs, (doc) => new Notification(doc))); resolve(map(docs, (doc) => new Notification(doc)));
}); });
}); });
} }

View File

@ -1,4 +1,5 @@
const _ = require('lodash'); const map = require('lodash/map');
const filter = require('lodash/filter');
class Upload class Upload
@ -61,9 +62,9 @@ class UploadRepository
userId: userId, userId: userId,
code: code, code: code,
expiration: expiration, expiration: expiration,
files: _.map(_.filter(files, files: map(filter(files,
(file) => file.hasOwnProperty('id') && file.hasOwnProperty('name')), (file) => file.hasOwnProperty('id') && file.hasOwnProperty('name')),
(file) => { return { id: file.id, name: file.name, size: file.size } }) (file) => { return { id: file.id, name: file.name, size: file.size } })
}; };
if (upload.files.length) if (upload.files.length)

View File

@ -1,4 +1,4 @@
const _ = require('lodash'); const map = require('lodash/map');
const AuthTokens = require('../authtokens'); const AuthTokens = require('../authtokens');
const bcrypt = require('bcrypt'); const bcrypt = require('bcrypt');
@ -121,7 +121,7 @@ class UserRepository
return; return;
} }
resolve(_.map(docs, (doc) => new User(doc))); resolve(map(docs, (doc) => new User(doc)));
}); });
}); });
} }

83
package-lock.json generated
View File

@ -1520,6 +1520,17 @@
"callsite": "1.0.0" "callsite": "1.0.0"
} }
}, },
"bfj-node4": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/bfj-node4/-/bfj-node4-5.3.1.tgz",
"integrity": "sha512-SOmOsowQWfXc7ybFARsK3C4MCOWzERaOMV/Fl3Tgjs+5dJWyzo3oa127jL44eMbQiAN17J7SvAs2TRxEScTUmg==",
"dev": true,
"requires": {
"bluebird": "3.5.1",
"check-types": "7.3.0",
"tryer": "1.0.0"
}
},
"big.js": { "big.js": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
@ -2138,6 +2149,12 @@
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
"dev": true "dev": true
}, },
"check-types": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/check-types/-/check-types-7.3.0.tgz",
"integrity": "sha1-Ro9XGkQ1wkJI9f0MsOjYfDw0Hn0=",
"dev": true
},
"cheerio": { "cheerio": {
"version": "0.22.0", "version": "0.22.0",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz",
@ -3245,6 +3262,12 @@
"run-parallel": "1.1.8" "run-parallel": "1.1.8"
} }
}, },
"duplexer": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
"integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
"dev": true
},
"duplexer3": { "duplexer3": {
"version": "0.1.4", "version": "0.1.4",
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
@ -3977,6 +4000,12 @@
"integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
"dev": true "dev": true
}, },
"filesize": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz",
"integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==",
"dev": true
},
"fill-range": { "fill-range": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
@ -5486,6 +5515,16 @@
"lodash": "4.17.5" "lodash": "4.17.5"
} }
}, },
"gzip-size": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-4.1.0.tgz",
"integrity": "sha1-iuCWJX6r59acRb4rZ8RIEk/7UXw=",
"dev": true,
"requires": {
"duplexer": "0.1.1",
"pify": "3.0.0"
}
},
"har-schema": { "har-schema": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@ -12631,6 +12670,12 @@
"mimic-fn": "1.2.0" "mimic-fn": "1.2.0"
} }
}, },
"opener": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz",
"integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=",
"dev": true
},
"opn": { "opn": {
"version": "5.3.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz",
@ -15746,6 +15791,12 @@
} }
} }
}, },
"tryer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.0.tgz",
"integrity": "sha1-Antp+oIyJeVRys4+8DsR9qs3wdc=",
"dev": true
},
"tty-browserify": { "tty-browserify": {
"version": "0.0.0", "version": "0.0.0",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
@ -18615,6 +18666,38 @@
} }
} }
}, },
"webpack-bundle-analyzer": {
"version": "2.11.1",
"resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.11.1.tgz",
"integrity": "sha512-VKUVkVMc6TWVXmF1OxsBXoiRjYiDRA4XT0KqtbLMDK+891VX7FCuklYwzldND8J2upUcHHnuXYNTP+4mSFi4Kg==",
"dev": true,
"requires": {
"acorn": "5.5.3",
"bfj-node4": "5.3.1",
"chalk": "2.3.2",
"commander": "2.15.1",
"ejs": "2.5.9",
"express": "4.16.3",
"filesize": "3.6.1",
"gzip-size": "4.1.0",
"lodash": "4.17.5",
"mkdirp": "0.5.1",
"opener": "1.4.3",
"ws": "4.1.0"
},
"dependencies": {
"ws": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz",
"integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==",
"dev": true,
"requires": {
"async-limiter": "1.0.0",
"safe-buffer": "5.1.1"
}
}
}
},
"webpack-cli": { "webpack-cli": {
"version": "2.0.13", "version": "2.0.13",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-2.0.13.tgz", "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-2.0.13.tgz",

View File

@ -5,6 +5,7 @@
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"dev": "supervisor -w index.js,lib index.js", "dev": "supervisor -w index.js,lib index.js",
"devbuild": "webpack --mode development",
"build": "webpack --mode production", "build": "webpack --mode production",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
@ -64,6 +65,7 @@
"vue-style-loader": "^4.1.0", "vue-style-loader": "^4.1.0",
"vue-template-compiler": "^2.5.16", "vue-template-compiler": "^2.5.16",
"webpack": "^4.2.0", "webpack": "^4.2.0",
"webpack-bundle-analyzer": "^2.11.1",
"webpack-cli": "^2.0.13", "webpack-cli": "^2.0.13",
"webpack-dev-middleware": "^3.0.1", "webpack-dev-middleware": "^3.0.1",
"webpack-hot-middleware": "^2.21.2" "webpack-hot-middleware": "^2.21.2"

View File

@ -13,7 +13,6 @@
</template> </template>
<script> <script>
import _ from 'lodash';
import shared from './shared'; import shared from './shared';

View File

@ -6,25 +6,32 @@ import messages from './lang';
import shared from './shared'; import shared from './shared';
import fontawesome from '@fortawesome/fontawesome'; import fontawesome from '@fortawesome/fontawesome';
import FontAwesomeIcon from '@fortawesome/vue-fontawesome'; import FontAwesomeIcon from '@fortawesome/vue-fontawesome';
import solid from '@fortawesome/fontawesome-free-solid';
import moment from 'moment' import moment from 'moment'
import merge from 'lodash/merge';
// Implicitly import the icons used, saves a lot of space in the bundle.
// Perhaps vue-fontawesome will make this easier in the upcoming release?
// See: https://github.com/FortAwesome/vue-fontawesome/issues/46
import faSpinner from '@fortawesome/fontawesome-free-solid/faSpinner';
import faBan from '@fortawesome/fontawesome-free-solid/faBan';
import faTrashAlt from '@fortawesome/fontawesome-free-solid/faTrashAlt';
if (typeof customMessages !== 'undefined') if (typeof customMessages !== 'undefined')
{ {
_.merge(messages, customMessages); merge(messages, customMessages);
if (customMessages.hasOwnProperty('allLocales')) if (customMessages.hasOwnProperty('allLocales'))
{ {
for (var key in messages) for (var key in messages)
{ {
if (key !== 'allLocales' && messages.hasOwnProperty(key)) if (key !== 'allLocales' && messages.hasOwnProperty(key))
_.merge(messages[key], customMessages.allLocales); merge(messages[key], customMessages.allLocales);
} }
} }
} }
fontawesome.library.add(solid); fontawesome.library.add(faSpinner, faBan, faTrashAlt);
Vue.component('fa', FontAwesomeIcon); Vue.component('fa', FontAwesomeIcon);
Vue.use(VueI18n); Vue.use(VueI18n);

View File

@ -14,7 +14,7 @@
</template> </template>
<script> <script>
import _ from 'lodash'; import map from 'lodash/map';
import shared from '../shared'; import shared from '../shared';
import Uppy from 'uppy/lib/core'; import Uppy from 'uppy/lib/core';
import Dashboard from 'uppy/lib/plugins/Dashboard'; import Dashboard from 'uppy/lib/plugins/Dashboard';
@ -88,7 +88,7 @@ export default {
self.uppy.on('complete', (result) => self.uppy.on('complete', (result) =>
{ {
axios.post('/complete', { axios.post('/complete', {
files: _.map(result.successful, (file) => files: map(result.successful, (file) =>
{ {
return { return {
id: file.tus.uploadUrl.substr(file.tus.uploadUrl.lastIndexOf('/') + 1), id: file.tus.uploadUrl.substr(file.tus.uploadUrl.lastIndexOf('/') + 1),

View File

@ -41,6 +41,8 @@
<script> <script>
import axios from 'axios'; import axios from 'axios';
import shared from '../../shared'; import shared from '../../shared';
import orderBy from 'lodash/orderBy';
import findIndex from 'lodash/findIndex';
export default { export default {
data() data()
@ -62,7 +64,7 @@ export default {
}) })
.then((response) => .then((response) =>
{ {
self.codes = _.orderBy(response.data, ['created'], ['desc']); self.codes = orderBy(response.data, ['created'], ['desc']);
}) })
.catch((error) => { shared.$emit('apiError', error, this.$router) }); .catch((error) => { shared.$emit('apiError', error, this.$router) });
}, },
@ -89,7 +91,7 @@ export default {
}}) }})
.then((response) => .then((response) =>
{ {
var index = _.findIndex(self.codes, (item) => { return item.id == codeId; }); var index = findIndex(self.codes, (item) => { return item.id == codeId; });
if (index > -1) if (index > -1)
self.codes.splice(index, 1); self.codes.splice(index, 1);
}) })

View File

@ -43,7 +43,8 @@
</template> </template>
<script> <script>
import _ from 'lodash'; import orderBy from 'lodash/orderBy';
import findIndex from 'lodash/findIndex';
import axios from 'axios'; import axios from 'axios';
import shared from '../../shared'; import shared from '../../shared';
@ -74,7 +75,7 @@ export default {
}) })
.then((response) => .then((response) =>
{ {
self.uploads = _.orderBy(response.data, ['created'], ['desc']); self.uploads = orderBy(response.data, ['created'], ['desc']);
}) })
.catch((error) => { shared.$emit('apiError', error, this.$router) }); .catch((error) => { shared.$emit('apiError', error, this.$router) });
}, },
@ -123,7 +124,7 @@ export default {
}}) }})
.then((response) => .then((response) =>
{ {
var index = _.findIndex(self.uploads, (item) => { return item.id == uploadId; }); var index = findIndex(self.uploads, (item) => { return item.id == uploadId; });
if (index > -1) if (index > -1)
self.uploads.splice(index, 1); self.uploads.splice(index, 1);
}) })

View File

@ -37,6 +37,8 @@
<script> <script>
import axios from 'axios'; import axios from 'axios';
import shared from '../../shared'; import shared from '../../shared';
import orderBy from 'lodash/orderBy';
import findIndex from 'lodash/findIndex';
export default { export default {
data() data()
@ -58,7 +60,7 @@ export default {
}) })
.then((response) => .then((response) =>
{ {
self.users = _.orderBy(response.data, ['active', 'username'], ['desc', 'asc']); self.users = orderBy(response.data, ['active', 'username'], ['desc', 'asc']);
}) })
.catch((error) => { shared.$emit('apiError', error, this.$router) }); .catch((error) => { shared.$emit('apiError', error, this.$router) });
}, },
@ -79,7 +81,7 @@ export default {
}}) }})
.then((response) => .then((response) =>
{ {
var index = _.findIndex(self.users, (item) => { return item.id == userId; }); var index = findIndex(self.users, (item) => { return item.id == userId; });
if (index > -1) if (index > -1)
self.users.splice(index, 1); self.users.splice(index, 1);
}) })

View File

@ -1,117 +1,122 @@
const path = require('path'); const path = require('path');
const webpack = require('webpack'); const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
mode: 'development',
entry: './public/src/app.js',
output: { module.exports = (env, options) => {
path: path.resolve(__dirname, './public/dist'),
publicPath: '/',
filename: 'build.js'
},
module: { let config = {
rules: [ mode: options.mode,
{ entry: './public/src/app.js',
test: /\.css$/,
use: [ output: {
'vue-style-loader', path: path.resolve(__dirname, './public/dist'),
'css-loader' publicPath: '/',
], filename: 'build.js'
}, },
{
test: /\.scss$/, module: {
use: [ rules: [
'vue-style-loader', {
'css-loader', test: /\.css$/,
'sass-loader' use: [
], 'vue-style-loader',
}, 'css-loader'
{ ],
test: /\.vue$/, },
loader: 'vue-loader', {
options: { test: /\.scss$/,
loaders: { use: [
'scss': [ 'vue-style-loader',
'vue-style-loader', 'css-loader',
'css-loader', 'sass-loader'
'sass-loader' ],
] },
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
'scss': [
'vue-style-loader',
'css-loader',
'sass-loader'
]
}
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
} }
} }
}, ]
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, './public/src/index.html')
})
],
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}, },
extensions: ['*', '.js', '.vue', '.json']
},
devServer: { plugins: [
historyApiFallback: true, new HtmlWebpackPlugin({
noInfo: true, template: path.resolve(__dirname, './public/src/index.html')
overlay: true })
}, ],
performance: { resolve: {
hints: false alias: {
}, 'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
},
devtool: '#eval-source-map' devServer: {
} historyApiFallback: true,
noInfo: true,
overlay: true
},
if (process.env.NODE_ENV === 'production') performance: {
{ hints: false
module.exports.devtool = '#source-map' },
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
]);
}
else
{
module.exports.entry = [
module.exports.entry,
'webpack-hot-middleware/client'
];
module.exports.plugins = (module.exports.plugins || []).concat([ devtool: '#eval-source-map'
new webpack.HotModuleReplacementPlugin(), };
new webpack.NoEmitOnErrorsPlugin()
]); if (options.mode === 'production')
} {
config.devtool = '#source-map'
config.plugins = (config.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
}),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
// To see what's using the space in the bundle, uncomment this
//new BundleAnalyzerPlugin()
]);
}
else
{
config.entry = [
config.entry,
'webpack-hot-middleware/client'
];
config.plugins = (config.plugins || []).concat([
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
]);
}
return config;
};