roadhog
Version:
Cli tool for serve and build react app, based on create-react-app, support JSON pattern config.
230 lines (218 loc) • 5.98 kB
JavaScript
import autoprefixer from 'autoprefixer';
import webpack from 'webpack';
import fs from 'fs';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import Visualizer from 'webpack-visualizer-plugin';
import CopyWebpackPlugin from 'copy-webpack-plugin';
import getEntry from '../utils/getEntry';
import getTheme from '../utils/getTheme';
import getCSSLoaders from '../utils/getCSSLoaders';
import normalizeDefine from '../utils/normalizeDefine';
import addExtraBabelIncludes from '../utils/addExtraBabelIncludes';
const baseSvgLoader = {
test: /\.svg$/,
loader: 'file',
query: {
name: 'static/[name].[hash:8].[ext]',
},
};
const spriteSvgLoader = {
test: /\.(svg)$/i,
loader: 'svg-sprite',
};
export default function (args, appBuild, config, paths) {
const { debug, analyze } = args;
const NODE_ENV = debug ? 'development' : process.env.NODE_ENV;
const {
publicPath = '/',
library = null,
libraryTarget = 'var',
devtool = null,
} = config;
const cssLoaders = getCSSLoaders(config);
const theme = JSON.stringify(getTheme(process.cwd(), config));
const output = {
path: appBuild,
filename: '[name].js',
publicPath,
libraryTarget,
chunkFilename: '[id].async.js',
};
if (library) output.library = library;
const finalWebpackConfig = {
bail: true,
entry: getEntry(config, paths.appDirectory, /* isBuild */true),
output,
resolve: {
extensions: [
'.web.js', '.web.jsx', '.web.ts', '.web.tsx',
'.js', '.json', '.jsx', '.ts', '.tsx', '',
],
},
resolveLoader: {
root: [
paths.ownNodeModules,
paths.appNodeModules,
],
moduleTemplates: ['*-loader'],
},
module: {
loaders: [
{
exclude: [
/\.html$/,
/\.(js|jsx)$/,
/\.(css|less)$/,
/\.json$/,
/\.svg$/,
/\.tsx?$/,
],
loader: 'url',
query: {
limit: 10000,
name: 'static/[name].[hash:8].[ext]',
},
},
{
test: /\.(js|jsx)$/,
include: paths.appSrc,
loader: 'babel',
},
{
test: /\.css$/,
include: paths.appSrc,
loader: ExtractTextPlugin.extract(
'style',
cssLoaders.own.join('!'),
),
},
{
test: /\.less$/,
include: paths.appSrc,
loader: ExtractTextPlugin.extract(
'style',
`${cssLoaders.own.join('!')}!less?{"modifyVars":${theme}}`,
),
},
{
test: /\.css$/,
include: paths.appNodeModules,
loader: ExtractTextPlugin.extract(
'style',
cssLoaders.nodeModules.join('!'),
),
},
{
test: /\.less$/,
include: paths.appNodeModules,
loader: ExtractTextPlugin.extract(
'style',
`${cssLoaders.nodeModules.join('!')}!less?{"modifyVars":${theme}}`,
),
},
{
test: /\.html$/,
loader: 'file?name=[name].[ext]',
},
{
test: /\.json$/,
loader: 'json',
},
{
test: /\.tsx?$/,
include: paths.appSrc,
loader: 'babel!awesome-typescript',
},
],
},
babel: {
presets: [
require.resolve('babel-preset-es2015'),
require.resolve('babel-preset-react'),
require.resolve('babel-preset-stage-0'),
],
plugins: [
require.resolve('babel-plugin-add-module-exports'),
require.resolve('babel-plugin-react-require'),
].concat(config.extraBabelPlugins || []),
cacheDirectory: true,
},
postcss() {
return [
autoprefixer(config.autoprefixer || {
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
}),
]
.concat(config.extraPostCSSPlugins ? config.extraPostCSSPlugins : []);
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(NODE_ENV),
},
}),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.DedupePlugin(),
new ExtractTextPlugin('[name].css'),
]
.concat(
debug ? [] : new webpack.optimize.UglifyJsPlugin({
compress: {
screw_ie8: true, // React doesn't support IE8
warnings: false,
},
mangle: {
screw_ie8: true,
},
output: {
comments: false,
screw_ie8: true,
ascii_only: true,
},
}),
)
.concat(
analyze ? new Visualizer() : [],
)
.concat(
!fs.existsSync(paths.appPublic) ? [] :
new CopyWebpackPlugin([
{
from: paths.appPublic,
to: appBuild,
},
]),
)
.concat(
!config.multipage ? [] :
new webpack.optimize.CommonsChunkPlugin('common', 'common.js'),
)
.concat(
!config.define ? [] :
new webpack.DefinePlugin(normalizeDefine(config.define)),
),
externals: config.externals,
node: {
fs: 'empty',
net: 'empty',
tls: 'empty',
},
};
if (devtool) finalWebpackConfig.devtool = devtool;
if (config.svgSpriteLoaderDirs) {
baseSvgLoader.exclude = config.svgSpriteLoaderDirs;
spriteSvgLoader.include = config.svgSpriteLoaderDirs;
finalWebpackConfig.module.loaders = finalWebpackConfig.module.loaders.concat([
baseSvgLoader,
spriteSvgLoader,
]);
} else {
finalWebpackConfig.module.loaders.push(baseSvgLoader);
}
return addExtraBabelIncludes(finalWebpackConfig, paths, config.extraBabelIncludes);
}