diff --git a/common/Root.tsx b/common/Root.tsx index efafe78c..8acf8417 100644 --- a/common/Root.tsx +++ b/common/Root.tsx @@ -11,10 +11,11 @@ import Swap from 'containers/Tabs/Swap'; import SignAndVerifyMessage from 'containers/Tabs/SignAndVerifyMessage'; import BroadcastTx from 'containers/Tabs/BroadcastTx'; import ErrorScreen from 'components/ErrorScreen'; +import { Store } from 'redux'; +import { AppState } from 'reducers'; -// TODO: fix this interface Props { - store: any; + store: Store; } interface State { diff --git a/common/api/utils.ts b/common/api/utils.ts index 199e65b7..8ff1e985 100644 --- a/common/api/utils.ts +++ b/common/api/utils.ts @@ -1,4 +1,4 @@ -import { indexOf } from 'lodash'; +import indexOf from 'lodash/indexOf'; export const filter = (i: any, arr: any[]) => { return -1 !== indexOf(arr, i) ? true : false; diff --git a/common/containers/Tabs/Swap/components/CurrencySwap.tsx b/common/containers/Tabs/Swap/components/CurrencySwap.tsx index 652ec39e..b9566877 100644 --- a/common/containers/Tabs/Swap/components/CurrencySwap.tsx +++ b/common/containers/Tabs/Swap/components/CurrencySwap.tsx @@ -7,7 +7,8 @@ import translate from 'translations'; import { combineAndUpper } from 'utils/formatters'; import { Dropdown } from 'components/ui'; import Spinner from 'components/ui/Spinner'; -import { without, intersection } from 'lodash'; +import intersection from 'lodash/intersection'; +import without from 'lodash/without'; import './CurrencySwap.scss'; export interface StateProps { diff --git a/common/index.html b/common/index.html index 52484dc8..d77f5fbf 100644 --- a/common/index.html +++ b/common/index.html @@ -7,7 +7,6 @@ - diff --git a/common/libs/nodes/rpc/utils.ts b/common/libs/nodes/rpc/utils.ts index 465471e2..1c7cd164 100644 --- a/common/libs/nodes/rpc/utils.ts +++ b/common/libs/nodes/rpc/utils.ts @@ -2,7 +2,7 @@ import BN from 'bn.js'; import { toBuffer, addHexPrefix, bufferToHex } from 'ethereumjs-util'; -import { trimStart } from 'lodash'; +import trimStart from 'lodash/trimStart'; // When encoding QUANTITIES (integers, numbers): encode as hex, prefix with "0x", the most compact representation (slight exception: zero should be represented as "0x0"). export function hexEncodeQuantity(value: BN | Buffer): string { diff --git a/common/libs/transaction/utils/index.ts b/common/libs/transaction/utils/index.ts index ebd75093..5176d0f1 100644 --- a/common/libs/transaction/utils/index.ts +++ b/common/libs/transaction/utils/index.ts @@ -2,7 +2,6 @@ import { Wei } from 'libs/units'; import * as eth from './ether'; import { IFullWallet } from 'libs/wallet'; import { ITransaction } from '../typings'; -export { signTransaction }; export { enoughBalanceViaTx, validateTx, @@ -12,7 +11,7 @@ export { computeIndexingHash } from './ether'; export * from './token'; -const signTransaction = async ( +export const signTransaction = async ( t: ITransaction, w: IFullWallet, accountBalance: Wei, diff --git a/common/libs/wallet/deterministic/trezor.ts b/common/libs/wallet/deterministic/trezor.ts index a681958b..7e2a8c9e 100644 --- a/common/libs/wallet/deterministic/trezor.ts +++ b/common/libs/wallet/deterministic/trezor.ts @@ -6,7 +6,7 @@ import TrezorConnect from 'vendor/trezor-connect'; import { DeterministicWallet } from './deterministic'; import { getTransactionFields } from 'libs/transaction'; -import { mapValues } from 'lodash'; +import mapValues from 'lodash/mapValues'; import { IFullWallet } from '../IWallet'; diff --git a/common/vendors.js b/common/vendors.js deleted file mode 100644 index 1b6bf554..00000000 --- a/common/vendors.js +++ /dev/null @@ -1,24 +0,0 @@ -require('ethereumjs-abi'); -require('ethereumjs-util'); -require('ethereumjs-wallet'); -require('hdkey'); -require('idna-uts46'); -require('lodash'); -require('react'); -require('react-dom'); -require('react-markdown'); -require('react-redux'); -require('react-router'); -require('react-router-redux'); -require('redux'); -require('redux-logger'); -require('redux-saga'); -require('wallet-address-validator'); -require('store2'); -require('whatwg-fetch'); -require('moment'); -require('prop-types'); -require('qrcode'); -require('qrcode.react'); -require('bn.js'); -require('classnames'); diff --git a/package.json b/package.json index f2f1951d..e6834e07 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "ethereumjs-util": "5.1.2", "ethereumjs-wallet": "0.6.0", "font-awesome": "4.7.0", + "hard-source-webpack-plugin": "^0.5.13", "hdkey": "0.7.1", "idna-uts46": "1.1.0", "jsonschema": "1.2.2", @@ -62,6 +63,7 @@ "@types/redux-promise-middleware": "0.0.9", "@types/uuid": "3.4.3", "@types/webpack-env": "1.13.3", + "autodll-webpack-plugin": "^0.3.8", "awesome-typescript-loader": "3.4.1", "babel-minify-webpack-plugin": "0.2.0", "bs58": "4.0.1", @@ -80,7 +82,6 @@ "friendly-errors-webpack-plugin": "1.6.1", "glob": "7.1.2", "hoist-non-react-statics": "2.3.1", - "html-webpack-include-assets-plugin": "1.0.2", "html-webpack-plugin": "2.30.1", "husky": "0.14.3", "image-webpack-loader": "3.4.2", @@ -102,7 +103,9 @@ "rimraf": "2.6.2", "sass-loader": "6.0.6", "style-loader": "0.19.1", + "thread-loader": "^1.1.2", "ts-jest": "22.0.0", + "ts-loader": "^3.2.0", "tslint": "5.8.0", "tslint-config-prettier": "1.6.0", "tslint-react": "3.3.3", @@ -135,7 +138,6 @@ "predev:https": "check-node-version --package", "tslint": "tslint --project . --exclude common/vendor/**/*", "tscheck": "tsc --noEmit", - "postinstall": "webpack --config=./webpack_config/webpack.dll.js", "start": "npm run dev", "precommit": "lint-staged", "formatAll": diff --git a/tsconfig.json b/tsconfig.json index 29c9d8bb..c22c42e2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,9 +3,9 @@ "outDir": "./dist/", "sourceMap": true, "strictNullChecks": true, - "module": "esnext", + "module": "es2015", "jsx": "react", - "target": "es5", + "target": "es2015", "allowJs": true, "baseUrl": "./common/", "lib": [ diff --git a/webpack_config/config.js b/webpack_config/config.js index 3b4dda0d..a5d6acfa 100644 --- a/webpack_config/config.js +++ b/webpack_config/config.js @@ -8,27 +8,38 @@ module.exports = { srcPath: path.join(__dirname, './../common'), // add these dependencies to a standalone vendor bundle vendor: [ + 'bip39', + 'bn.js', + 'classnames', + 'ethereum-blockies', + 'ethereumjs-abi', + 'ethereumjs-tx', + 'ethereumjs-util', + 'ethereumjs-wallet', + 'hdkey', + 'idna-uts46', + 'jsonschema', + 'lodash', + 'moment', + 'normalizr', + 'qrcode', + 'qrcode.react', + 'query-string', 'react', 'react-dom', - 'react-router', - 'redux', + 'react-markdown', + 'react-redux', + 'react-router-dom', 'react-router-redux', + 'react-transition-group', + 'redux', + 'redux-logger', + 'redux-promise-middleware', 'redux-saga', + 'scryptsy', + 'store2', + 'uuid', + 'wallet-address-validator', 'whatwg-fetch' - ], - // Settings for webpack-image-loader image compression - imageCompressionOptions: { - optipng: { - optimizationLevel: 4 - }, - gifsicle: { - interlaced: false - }, - mozjpeg: { - quality: 80 - }, - svgo: { - plugins: [{ removeViewBox: true }, { removeEmptyAttrs: false }, { sortAttrs: true }] - } - } + ] }; diff --git a/webpack_config/server.js b/webpack_config/server.js index e750f648..e5359788 100644 --- a/webpack_config/server.js +++ b/webpack_config/server.js @@ -39,8 +39,7 @@ const devMiddleWare = require('webpack-dev-middleware')(compiler, { 'Access-Control-Allow-Headers': '*' }, watchOptions: { - aggregateTimeout: 300, - poll: true + aggregateTimeout: 100 } }); app.use(devMiddleWare); diff --git a/webpack_config/utils.js b/webpack_config/utils.js index 5d0472eb..d3ecc8ce 100644 --- a/webpack_config/utils.js +++ b/webpack_config/utils.js @@ -19,6 +19,7 @@ _.loadersOptions = () => { return { minimize: isProd, + debug: !isProd, options: { // css-loader relies on context context: process.cwd() diff --git a/webpack_config/webpack.base.js b/webpack_config/webpack.base.js index 348693b4..3fb56ad1 100644 --- a/webpack_config/webpack.base.js +++ b/webpack_config/webpack.base.js @@ -4,11 +4,10 @@ const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const FaviconsWebpackPlugin = require('favicons-webpack-plugin'); -const HtmlWebpackIncludeAssetsPlugin = require('html-webpack-include-assets-plugin'); const config = require('./config'); const _ = require('./utils'); -const { CheckerPlugin } = require('awesome-typescript-loader'); -module.exports = { + +const webpackConfig = { entry: { client: './common/index.tsx' }, @@ -17,9 +16,6 @@ module.exports = { filename: '[name].js', publicPath: config.publicPath }, - performance: { - hints: process.env.NODE_ENV === 'production' ? 'warning' : false - }, resolve: { extensions: ['.ts', '.tsx', '.js', '.css', '.json', '.scss', '.less'], modules: [ @@ -30,23 +26,26 @@ module.exports = { ] }, module: { - loaders: [ + rules: [ { test: /\.(ts|tsx)$/, - loaders: [ - { loader: 'cache-loader' }, - { - loader: 'awesome-typescript-loader' - } - ], - exclude: [/node_modules/] + include: path.resolve(__dirname, '../common'), + use: [{ loader: 'ts-loader', options: { happyPackMode: true, logLevel: 'info' } }], + exclude: ['assets', 'sass', 'vendor', 'translations/lang'] + .map(dir => path.resolve(__dirname, `../common/${dir}`)) + .concat([path.resolve(__dirname, '../node_modules')]) }, { + include: [ + path.resolve(__dirname, '../common/assets'), + path.resolve(__dirname, '../node_modules') + ], + exclude: /node_modules(?!\/font-awesome)/, test: /\.(gif|png|jpe?g|svg)$/i, - loaders: [ + use: [ { loader: 'file-loader', - query: { + options: { hash: 'sha512', digest: 'hex', name: '[path][name].[ext]?[hash:6]' @@ -54,38 +53,52 @@ module.exports = { }, { loader: 'image-webpack-loader', - query: config.imageCompressionOptions + options: { + bypassOnDebug: true, + optipng: { + optimizationLevel: 4 + }, + gifsicle: { + interlaced: false + }, + mozjpeg: { + quality: 80 + }, + svgo: { + plugins: [{ removeViewBox: true }, { removeEmptyAttrs: false }, { sortAttrs: true }] + } + } } ] }, { + include: [ + path.resolve(__dirname, '../common/assets'), + path.resolve(__dirname, '../node_modules') + ], + exclude: /node_modules(?!\/font-awesome)/, test: /\.(ico|eot|otf|webp|ttf|woff|woff2)(\?.*)?$/, - loader: 'file-loader?limit=100000' + loader: 'file-loader' } ] }, plugins: [ - new webpack.DefinePlugin({ - 'process.env.BUILD_DOWNLOADABLE': JSON.stringify(!!process.env.BUILD_DOWNLOADABLE) - }), new HtmlWebpackPlugin({ title: config.title, template: path.resolve(__dirname, '../common/index.html'), + inject: true, filename: _.outputIndexPath }), - new HtmlWebpackIncludeAssetsPlugin({ assets: ['dll.vendor.js'], append: false }), - new FaviconsWebpackPlugin({ - logo: path.resolve(__dirname, '../static/favicon/android-chrome-384x384.png'), - background: '#163151' - }), - new webpack.LoaderOptionsPlugin(_.loadersOptions()), new CopyWebpackPlugin([ { from: _.cwd('./static'), // to the root of dist path to: './' } - ]) + ]), + + new webpack.LoaderOptionsPlugin(_.loadersOptions()) ], target: _.target }; +module.exports = webpackConfig; diff --git a/webpack_config/webpack.dev.js b/webpack_config/webpack.dev.js index 4bf406fa..dddcaf67 100644 --- a/webpack_config/webpack.dev.js +++ b/webpack_config/webpack.dev.js @@ -4,31 +4,78 @@ const path = require('path'); const webpack = require('webpack'); const base = require('./webpack.base'); const FriendlyErrors = require('friendly-errors-webpack-plugin'); +const AutoDllPlugin = require('autodll-webpack-plugin'); +const config = require('./config'); +const HardSourceWebpackPlugin = require('hard-source-webpack-plugin'); +const threadLoader = require('thread-loader'); -base.devtool = process.env.SLOW_BUILD_SPEED - ? 'source-map' - : 'cheap-module-eval-source-map'; +const fullSourceMap = process.env.SLOW_BUILD_SPEED; +if (fullSourceMap) { + base.devtool = fullSourceMap ? 'source-map' : 'cheap-module-eval-source-map'; -base.module.loaders.push( + threadLoader.warmup( + { + // pool options, like passed to loader options + // must match loader options to boot the correct pool + happyPackMode: true, + logLevel: 'info' + }, + [ + // modules to load + // can be any module, i. e. + 'ts-loader' + ] + ); + base.module.rules[0].use.unshift({ + loader: 'thread-loader', + options: { + workers: 4 + } + }); +} + +base.performance = { hints: false }; + +base.module.rules.push( { test: /\.css$/, - loaders: ['style-loader', 'css-loader'] + include: path.resolve(__dirname, '../common/vendor'), + use: ['style-loader', 'css-loader'] }, { test: /\.scss$/, - loaders: ['style-loader', 'css-loader', 'sass-loader'] + include: ['components', 'containers', 'sass'] + .map(dir => path.resolve(__dirname, `../common/${dir}`)) + .concat([path.resolve(__dirname, '../node_modules')]), + + exclude: /node_modules(?!\/font-awesome)/, + use: ['style-loader', 'css-loader', 'sass-loader'] }, { test: /\.less$/, - loaders: ['style-loader', 'css-loader', 'less-loader'] + include: path.resolve(__dirname, '../common/assets/styles'), + use: ['style-loader', 'css-loader', 'less-loader'] } ); base.plugins.push( - new webpack.DllReferencePlugin({ - context: path.join(__dirname, '../common'), - manifest: require('../dll/vendor-manifest.json') + new AutoDllPlugin({ + inject: true, // will inject the DLL bundles to index.html + filename: '[name]_[hash].js', + debug: true, + context: path.join(__dirname, '..'), + entry: { + vendor: [...config.vendor, 'babel-polyfill', 'bootstrap-sass', 'font-awesome'] + } }), + new HardSourceWebpackPlugin({ + environmentHash: { + root: process.cwd(), + directories: ['webpack_config'], + files: ['package.json'] + } + }), + new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('development') }), diff --git a/webpack_config/webpack.dll.js b/webpack_config/webpack.dll.js deleted file mode 100644 index bb39a778..00000000 --- a/webpack_config/webpack.dll.js +++ /dev/null @@ -1,31 +0,0 @@ -const path = require('path'); -const webpack = require('webpack'); -const config = require('./config'); -const _ = require('./utils'); - -module.exports = { - entry: { - vendor: [path.join(__dirname, '../common', 'vendors.js')] - }, - output: { - path: path.join(__dirname, '../static'), - filename: 'dll.[name].js', - library: '[name]' - }, - plugins: [ - new webpack.DllPlugin({ - path: path.join(__dirname, '../dll', '[name]-manifest.json'), - name: '[name]', - context: path.resolve(__dirname, '../common') - }) - ], - resolve: { - modules: [ - // places where to search for required modules - 'node_modules', - config.srcPath, - _.cwd('node_modules'), - _.cwd('./') - ] - } -}; diff --git a/webpack_config/webpack.freezer.js b/webpack_config/webpack.freezer.js index 9aba6d19..7fb20d0c 100644 --- a/webpack_config/webpack.freezer.js +++ b/webpack_config/webpack.freezer.js @@ -8,8 +8,8 @@ const freezerConfig = Object.assign({}, baseConfig, { target: undefined, performance: undefined, module: { - // Typescript loader - loaders: [baseConfig.module.loaders[0]] + // Typescript loader + loaders: [baseConfig.module.rules[0]] }, // Point at freezer, make sure it's setup to run in node diff --git a/webpack_config/webpack.prod.js b/webpack_config/webpack.prod.js index 2a1e7906..392e803a 100644 --- a/webpack_config/webpack.prod.js +++ b/webpack_config/webpack.prod.js @@ -1,6 +1,7 @@ 'use strict'; process.env.NODE_ENV = 'production'; - +const FaviconsWebpackPlugin = require('favicons-webpack-plugin'); +const path = require('path'); const webpack = require('webpack'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const ProgressPlugin = require('webpack/lib/ProgressPlugin'); @@ -14,8 +15,8 @@ const distFolder = 'dist/'; // Clear out build folder rimraf.sync(distFolder, { rmdirSync: true }); -base.devtool = 'source-map'; -base.module.loaders.push( +base.devtool = false; +base.module.rules.push( { test: /\.css$/, use: ExtractTextPlugin.extract({ @@ -43,15 +44,24 @@ base.entry.vendor = config.vendor; // use hash filename to support long-term caching base.output.filename = '[name].[chunkhash:8].js'; // add webpack plugins +base.plugins.unshift( + new FaviconsWebpackPlugin({ + logo: path.resolve(__dirname, '../static/favicon/android-chrome-384x384.png'), + background: '#163151', + inject: true + }) +); + base.plugins.push( new ProgressPlugin(), new ExtractTextPlugin('[name].[chunkhash:8].css'), + new webpack.DefinePlugin({ + 'process.env.BUILD_DOWNLOADABLE': JSON.stringify(!!process.env.BUILD_DOWNLOADABLE) + }), new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') }), - new BabelMinifyPlugin(undefined, { - comments: false - }), + new BabelMinifyPlugin(), // extract vendor chunks new webpack.optimize.CommonsChunkPlugin({ name: 'vendor',