react-cordova-boilerplate
Version:
TodoMVC example for react with development tools to build a cordova application
255 lines (240 loc) • 7.09 kB
JavaScript
const webpack = require('webpack');
const path = require('path');
const nodeExternals = require('webpack-node-externals');
// Plugins
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const rootPath = path.join(__dirname, '..');
let getServerString;
/**
* Getter for webpack config for all the different kind of builds there is in this repo
* @param {Object} options Passed from building, starting and testing the application
* @param {Object} privateOptions Only passed from `getServerString`, used to add some private options relevent only to this file
* @return {Object} Webpack config object
*/
const getWebpackConfig = (options = ({}), privateOptions = ({})) => {
const {
coveragePaths = [],
isProd = false,
isSsr = false,
isWebpackDevServer = false,
isTest = false,
port,
bail = false,
globals = ({})
} = options;
const {
isClientBuild = true
} = privateOptions;
return ({
bail,
target: isTest ? 'node' : undefined,
devtool: isTest ? 'inline-source-map' : (isProd ? false : 'source-map'),
entry: isTest ? undefined : {
[`app${isProd ? '.min' : ''}`]: (
isWebpackDevServer ? [`webpack-dev-server/client?http://localhost:${port}`, 'webpack/hot/dev-server'] : []
).concat(path.join(rootPath, 'src', 'entry-points', isClientBuild ? 'client.jsx' : 'server.jsx'))
},
output: isTest ? undefined : {
path: path.join(rootPath, 'www'),
filename: '[name].js',
libraryTarget: isClientBuild ? undefined : 'umd'
},
plugins: [
new ExtractTextPlugin({
filename: '[name].css',
disable: isWebpackDevServer,
allChunks: true
}),
new webpack.DefinePlugin(
Object.assign({
__PROD__: JSON.stringify(isProd),
__DEV__: JSON.stringify(!isProd),
__DEVSERVER__: JSON.stringify(isWebpackDevServer),
__DEVTOOLS__: JSON.stringify(isWebpackDevServer),
__CLIENT__: JSON.stringify(isClientBuild),
__SERVER__: JSON.stringify(!isClientBuild),
'process.env': {
NODE_ENV: JSON.stringify(isProd ? 'production' : 'development')
}
},
Object.keys(globals).reduce( // Stringify all the globals
(obj, k) => Object.assign(obj, {
[k]: JSON.stringify(globals[k])
}),
{}
)
)
)
]
.concat(isClientBuild ? [
new HtmlWebpackPlugin({
minify: {},
getAppContent: () => (isSsr ? getServerString(options) : ''),
template: path.join(rootPath, 'src', 'index.ejs'),
inject: 'body'
})
] : [])
.concat(isTest ? [] : new webpack.ProvidePlugin({
fetch: 'imports?this=>global!exports?global.fetch!whatwg-fetch'
}))
.concat(isWebpackDevServer ? [
new webpack.HotModuleReplacementPlugin()
] : [])
.concat(isProd ? [
new webpack.optimize.UglifyJsPlugin({
output: {
comments: false
}
})
] : []),
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['es2015', 'stage-2'],
plugins: ['transform-runtime']
}
}
]
},
{
test: /\.jsx$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['es2015', 'stage-2', 'react'].concat(isWebpackDevServer ? ['react-hmre'] : []),
plugins: ['transform-runtime']
}
}
]
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: [
{
loader: 'css-loader'
}
],
fallback: 'style-loader'
})
}, {
test: /\.scss$/,
use: ExtractTextPlugin.extract({
use: [
{
loader: 'css-loader'
},
{
loader: 'resolve-url-loader',
options: {
fail: true
}
},
{
loader: 'sass-loader'
}
],
fallback: 'style-loader'
})
}, {
test: /\.woff(2)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
name: './font/[hash].[ext]',
mimetype: 'application/font-woff'
}
}
]
}, {
test: /\.(ttf|eot|svg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
name: './font/[hash].[ext]'
}
}
]
}, {
test: /\.(gif|png)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
name: './asset/[hash].[ext]'
}
}
]
}
]
.concat(isTest ? [
{
test: /\.(js|jsx)$/,
include: coveragePaths,
enforce: 'post',
loader: {
loader: 'istanbul-instrumenter-loader'
}
}
] : [])
},
resolve: {
modules: [
rootPath,
path.join(rootPath, 'node_modules')
]
},
externals: []
.concat(isTest ? nodeExternals() : [])
});
};
/**
* Sync getter for the server rendered app, good for showing something on the page while javascript execute on initial load
* @param {Object} options Passed as is from `getWebpackConfig`
* @return {String} String which contains the server rendered app
*/
getServerString = options => {
// Requiring dependencies here because there is no need or use while running eslint (which also imports webpack config).
// Some packages like `deasync` fail while running from some IDE's
/* eslint-disable global-require */
const requireFromString = require('require-from-string');
const MemoryFS = require('memory-fs');
const deasync = require('deasync');
/* eslint-enable global-require */
const { isProd } = options;
const bundlePath = path.join(rootPath, 'www', `app${isProd ? '.min' : ''}.js`);
const fs = new MemoryFS();
const compiler = webpack(
getWebpackConfig(options, { isClientBuild: false })
);
let sync = true;
let data = null;
compiler.outputFileSystem = fs;
compiler.run(err => {
if (err) {
throw err;
}
const fileContent = fs.readFileSync(bundlePath).toString('ascii');
data = requireFromString(fileContent);
sync = false;
});
while (sync) {
deasync.sleep(100);
}
return data;
};
module.exports = getWebpackConfig;