From 0fd652ab9399c9827d71da48df7e7859f90f9baf Mon Sep 17 00:00:00 2001 From: Daniel Ternyak Date: Tue, 11 Apr 2017 23:59:58 -0500 Subject: [PATCH] create webpack config with less support for both dev and prod --- webpack_config/config.js | 18 +++++++ webpack_config/log-plugin.js | 15 ++++++ webpack_config/server.js | 57 +++++++++++++++++++++++ webpack_config/utils.js | 28 +++++++++++ webpack_config/webpack.base.js | 85 ++++++++++++++++++++++++++++++++++ webpack_config/webpack.dev.js | 30 ++++++++++++ webpack_config/webpack.prod.js | 76 ++++++++++++++++++++++++++++++ 7 files changed, 309 insertions(+) create mode 100644 webpack_config/config.js create mode 100644 webpack_config/log-plugin.js create mode 100644 webpack_config/server.js create mode 100644 webpack_config/utils.js create mode 100644 webpack_config/webpack.base.js create mode 100644 webpack_config/webpack.dev.js create mode 100644 webpack_config/webpack.prod.js diff --git a/webpack_config/config.js b/webpack_config/config.js new file mode 100644 index 00000000..5f8b2a34 --- /dev/null +++ b/webpack_config/config.js @@ -0,0 +1,18 @@ +'use strict' +const path = require('path') + +module.exports = { + port: 3000, + title: 'React-Semantic.UI-starter', + publicPath: process.env.BUILD_GH_PAGES ? '/react-semantic.ui-starter/' : '/', + srcPath: path.join(__dirname, './../common'), + // add these dependencies to a standalone vendor bundle + vendor: [ + 'react', 'react-dom', 'react-router', 'redux', 'react-router-redux', 'redux-thunk', 'semantic-ui-react', 'whatwg-fetch', 'semantic-ui-css/semantic.css' + ], + // enable babelrc + babel: { + babelrc: true + }, + cssModules: false +} diff --git a/webpack_config/log-plugin.js b/webpack_config/log-plugin.js new file mode 100644 index 00000000..073c28d9 --- /dev/null +++ b/webpack_config/log-plugin.js @@ -0,0 +1,15 @@ +'use strict' +const chalk = require('chalk') + +// this plugin if for loggin url after each time the compilation is done. +module.exports = class LogPlugin { + constructor(port) { + this.port = port + } + + apply(compiler) { + compiler.plugin('done', () => { + console.log(`> App is running at ${chalk.yellow(`http://localhost:${this.port}`)}\n`) + }) + } +} diff --git a/webpack_config/server.js b/webpack_config/server.js new file mode 100644 index 00000000..ee7cff88 --- /dev/null +++ b/webpack_config/server.js @@ -0,0 +1,57 @@ +'use strict' +const path = require('path') +const express = require('express') +const webpack = require('webpack') +const webpackConfig = require('./webpack.dev') +const config = require('./config') +const LogPlugin = require('./log-plugin') + +const app = express() + +const port = config.port +webpackConfig.entry.client = [ + 'react-hot-loader/patch', + 'webpack-hot-middleware/client?reload=true', + 'webpack/hot/only-dev-server', + webpackConfig.entry.client +] + +webpackConfig.plugins.push(new LogPlugin(port)) + +let compiler + +try { + compiler = webpack(webpackConfig) +} catch (err) { + console.log(err.message) + process.exit(1) +} + +const devMiddleWare = require('webpack-dev-middleware')(compiler, { + publicPath: webpackConfig.output.publicPath, + quiet: false, + inline: true, + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*', + 'Access-Control-Allow-Headers': '*' + } +}) +app.use(devMiddleWare) +app.use(require('webpack-hot-middleware')(compiler, { + log: console.log +})) + +const mfs = devMiddleWare.fileSystem +const file = path.join(webpackConfig.output.path, 'index.html') + +devMiddleWare.waitUntilValid() + +app.get('*', (req, res) => { + devMiddleWare.waitUntilValid(() => { + const html = mfs.readFileSync(file) + res.end(html) + }) +}) + +app.listen(port) diff --git a/webpack_config/utils.js b/webpack_config/utils.js new file mode 100644 index 00000000..8e041488 --- /dev/null +++ b/webpack_config/utils.js @@ -0,0 +1,28 @@ +'use strict' +const path = require('path') +const config = require('./config') + +const _ = module.exports = {} + +_.cwd = (file) => { + return path.join(process.cwd(), file || '') +} + +_.outputPath = path.join(__dirname, '../dist') + +_.outputIndexPath = path.join(__dirname, '../dist/index.html') + +_.target = 'web' + +_.loadersOptions = () => { + const isProd = process.env.NODE_ENV === 'production' + + return { + minimize: isProd, + options: { + // css-loader relies on context + context: process.cwd(), + babel: config.babel + } + } +} diff --git a/webpack_config/webpack.base.js b/webpack_config/webpack.base.js new file mode 100644 index 00000000..0e33b674 --- /dev/null +++ b/webpack_config/webpack.base.js @@ -0,0 +1,85 @@ +'use strict' +const path = require('path') +const webpack = require('webpack') +const HtmlWebpackPlugin = require('html-webpack-plugin') +const CopyWebpackPlugin = require('copy-webpack-plugin') +const config = require('./config') +const _ = require('./utils') + +module.exports = { + entry: { + client: './common/index.jsx' + }, + output: { + path: _.outputPath, + filename: '[name].js', + publicPath: config.publicPath + }, + performance: { + hints: process.env.NODE_ENV === 'production' + ? 'warning' + : false + }, + resolve: { + extensions: [ + '.js', '.jsx', '.css', '.json', '.scss', '.less' + ], + alias: { + actions: `${config.srcPath}/actions/`, + api: `${config.srcPath}/api/`, + reducers: `${config.srcPath}/reducers/`, + components: `${config.srcPath}/components/`, + containers: `${config.srcPath}/containers/`, + styles: `${config.srcPath}/styles/`, + less_vars: `${config.srcPath}/styles/etherwallet-variables.less`, + scss_vars: `${config.srcPath}/styles/vars.scss`, + config: `${config.srcPath}/config/` + process.env.REACT_WEBPACK_ENV + }, + modules: [ + // places where to search for required modules + _.cwd('common'), + _.cwd('node_modules'), + _.cwd('./') + ] + }, + module: { + loaders: [ + { + test: /\.(js|jsx)$/, + enforce: 'pre', + loaders: ['eslint-loader'], + exclude: [/node_modules/] + }, + { + test: /\.(js|jsx)$/, + loaders: ['babel-loader'], + exclude: [/node_modules/] + }, { + test: /\.(ico|jpg|png|gif|eot|otf|webp|ttf|woff|woff2)(\?.*)?$/, + loader: 'file-loader?limit=100000' + }, { + test: /\.svg$/, + loader: 'file-loader' + } + ] + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env.BUILD_GH_PAGES': JSON.stringify(!!process.env.BUILD_GH_PAGES) + }), + new HtmlWebpackPlugin({ + title: config.title, + template: path.resolve(__dirname, '../common/index.html'), + filename: _.outputIndexPath + }), + new webpack.LoaderOptionsPlugin(_.loadersOptions()), + new CopyWebpackPlugin([ + { + from: _.cwd('./static'), + // to the root of dist path + to: './' + } + ]) + ], + target: _.target +} diff --git a/webpack_config/webpack.dev.js b/webpack_config/webpack.dev.js new file mode 100644 index 00000000..f9160ec2 --- /dev/null +++ b/webpack_config/webpack.dev.js @@ -0,0 +1,30 @@ +'use strict' +process.env.NODE_ENV = 'development' +process.env.REACT_WEBPACK_ENV = 'dev' + +const webpack = require('webpack') +const base = require('./webpack.base') +const FriendlyErrors = require('friendly-errors-webpack-plugin') + +base.devtool = 'eval-source-map' +base.module.loaders.push({ + test: /\.css$/, + loaders: ['style-loader', 'css-loader', 'resolve-url-loader'] + }, { + test: /\.scss$/, + loaders: ['style-loader', 'css-loader', 'resolve-url-loader', 'sass-loader'] + }, + { + test: /\.less$/, + loaders: ['style-loader', 'css-loader', 'resolve-url-loader', 'less-loader'] + }) +base.plugins.push( + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify('development') + }), + new webpack.HotModuleReplacementPlugin(), + new webpack.NoEmitOnErrorsPlugin(), + new FriendlyErrors() +) + +module.exports = base diff --git a/webpack_config/webpack.prod.js b/webpack_config/webpack.prod.js new file mode 100644 index 00000000..c1dce874 --- /dev/null +++ b/webpack_config/webpack.prod.js @@ -0,0 +1,76 @@ +'use strict' +process.env.NODE_ENV = 'production' +process.env.REACT_WEBPACK_ENV = 'dist' + +const exec = require('child_process').execSync +const webpack = require('webpack') +const ExtractTextPlugin = require('extract-text-webpack-plugin') +const ProgressPlugin = require('webpack/lib/ProgressPlugin') +// const OfflinePlugin = require('offline-plugin') +const base = require('./webpack.base') +const config = require('./config') + + +exec('rm -rf dist/') +base.devtool = 'cheap-source-map' +base.module.loaders.push( + { + test: /\.css$/, + use: ExtractTextPlugin.extract({fallback: 'style-loader', use: 'css-loader'}) + }, { + test: /\.scss$/, + use: ExtractTextPlugin.extract({fallback: 'style-loader', use: ['css-loader', 'sass-loader']}), + }, + { + test: /\.less$/, + use: ExtractTextPlugin.extract({fallback: 'style-loader', use: ['css-loader', 'sass-loader']}) + } +) +// a white list to add dependencies to vendor chunk +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.push( + new ProgressPlugin(), + new ExtractTextPlugin('[name].[chunkhash:8].css'), + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify('production') + }), + new webpack.optimize.UglifyJsPlugin({ + sourceMap: true, + compress: { + warnings: false + }, + output: { + comments: false + } + }), + // extract vendor chunks + new webpack.optimize.CommonsChunkPlugin({ + name: 'vendor', + filename: 'vendor.[chunkhash:8].js' + }) + // For progressive web apps + // new OfflinePlugin({ + // relativePaths: false, + // AppCache: false, + // ServiceWorker: { + // events: true + // } + // }) +) + +// minimize webpack output +base.stats = { + // Add children information + children: false, + // Add chunk information (setting this to `false` allows for a less verbose output) + chunks: false, + // Add built modules information to chunk information + chunkModules: false, + chunkOrigins: false, + modules: false +} + +module.exports = base