spinacia-script
Version:
spinacia script
354 lines (347 loc) • 11.4 kB
JavaScript
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
const PnpWebpackPlugin = require('pnp-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const safePostCssParser = require('postcss-safe-parser');
const postcssNormalize = require('postcss-normalize');
const WebpackAssetsManifest = require('webpack-assets-manifest');
const WebpackBar = require('webpackbar');
const getCacheIdentifier = require('./utils/getCacheIdentifier');
const paths = require('./path');
const {ENV_CONF, ESLINT} = require('./path');
const postcssOption = {
// Options for PostCSS as we reference these options twice
// Adds vendor prefixing based on your specified browser support in
// package.json
'loader': require.resolve('postcss-loader'),
'options': {
// Necessary for external CSS imports to work
// https://github.com/facebook/create-react-app/issues/2677
'ident': 'postcss',
'plugins': () => [
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
'autoprefixer': {
'flexbox': 'no-2009',
},
'stage': 3,
}),
// Adds PostCSS Normalize as the reset css with default options,
// so that it honors browserslist config in package.json
// which in turn let's users customize the target behavior as per their needs.
postcssNormalize(),
],
'sourceMap': false
},
};
module.exports = {
'devtool': 'source-map',
// Stop compilation early in production
'bail': true,
'entry': {
'app': paths.appIndexJs
},
'output': {
'path': paths.appOutputDir,
'chunkFilename': 'static/js/[name].[contenthash:8].chunk.js',
'filename': 'static/js/[name].[contenthash:8].js',
'publicPath': paths.publicPath,
'devtoolModuleFilenameTemplate': info => path
.relative(paths.appSrc, info.absoluteResourcePath)
.replace(/\\/g, '/')
},
'externals': {
'react': 'React',
'react-dom': 'ReactDOM',
'react-thunk': 'ReactThunk'
},
'recordsPath': paths.records,
'optimization': {
'minimize': true,
'splitChunks': {
'chunks': 'all',
},
'runtimeChunk': true,
'minimizer': [
new TerserJSPlugin({
'terserOptions': {
'parse': {
// we want terser to parse ecma 8 code. However, we don't want it
// to apply any minfication steps that turns valid ecma 5 code
// into invalid ecma 5 code. This is why the 'compress' and 'output'
// sections only apply transformations that are ecma 5 safe
// https://github.com/facebook/create-react-app/pull/4234
'ecma': 8,
},
'compress': {
'ecma': 5,
'warnings': false,
// Disabled because of an issue with Uglify breaking seemingly valid code:
// https://github.com/facebook/create-react-app/issues/2376
// Pending further investigation:
// https://github.com/mishoo/UglifyJS2/issues/2011
'comparisons': false,
// Disabled because of an issue with Terser breaking valid code:
// https://github.com/facebook/create-react-app/issues/5250
// Pending futher investigation:
// https://github.com/terser-js/terser/issues/120
'inline': 2,
},
'mangle': {
'safari10': true,
},
'output': {
'ecma': 5,
'comments': false,
// Turned on because emoji and regex is not minified properly using default
// https://github.com/facebook/create-react-app/issues/2488
'ascii_only': true,
},
},
// Use multi-process parallel running to improve the build speed
// Default number of concurrent runs: os.cpus().length - 1
'parallel': true,
// Enable file caching
'cache': true,
'sourceMap': true
}),
new OptimizeCssAssetsPlugin({
'cssProcessorOptions': {
'parser': safePostCssParser,
'map': {
// 不生成内联映射,这样配置就会生成一个source-map文件
'inline': false,
// 向css文件添加source-map路径注释
// 如果没有此项压缩后的css会去除source-map路径注释
'annotation': true
}
}
})
]
},
'plugins': [
new WebpackBar({
'name': '[SPINACIA][BUILD]',
'profile': false,
'basic': false
}),
new CaseSensitivePathsPlugin(),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
'filename': 'static/css/[name].[contenthash:8].css'
}),
new HtmlWebpackPlugin(Object.assign(
{
'title': typeof ENV_CONF.documentTitle === 'string' ? ENV_CONF.documentTitle : 'spinacia-react-redux',
'template': paths.appHtml,
'inject': true,
'favicon': paths.favicon,
'minify': {
'removeComments': true,
'collapseWhitespace': true,
'removeRedundantAttributes': true,
'useShortDoctype': true,
'removeEmptyAttributes': true,
'removeStyleLinkTypeAttributes': true,
'keepClosingSlash': true,
'minifyJS': true,
'minifyCSS': true,
'minifyURLs': true
},
'loading': {
'html': fs.readFileSync(paths.loadingHtml),
'css': `<style>${fs.readFileSync(paths.loadingCss)}</style>`
}
},
paths.assetsCdn,
paths.assetsLib
)),
new CleanWebpackPlugin(),
new WebpackAssetsManifest({
'output': 'build-assets.json',
publicPath(filename) {
const assetsPath = paths.getServedPath(filename);
if (assetsPath) {
return assetsPath;
} else {
return filename;
}
}
}),
new webpack.HashedModuleIdsPlugin()
].concat(process.env.TRAVIS_CI ? [] : [
new webpack.DefinePlugin({'process.env.ORIGIN_ENV': JSON.stringify(ENV_CONF.origin)}),
new webpack.optimize.ModuleConcatenationPlugin()
]),
'resolve': {
'extensions': ['.js', '.jsx'],
'plugins': [
// Adds support for installing with Plug'n'Play, leading to faster installs and adding
// guards against forgotten dependencies and such.
PnpWebpackPlugin
]
},
'resolveLoader': {
'plugins': [
// Also related to Plug'n'Play, but this time it tells Webpack to load its loaders
// from the current package.
PnpWebpackPlugin.moduleLoader(module),
]
},
'module': {
'rules': [
// First, run the linter.
// It's important to do this before Babel processes the JS.
ESLINT && typeof ESLINT === 'boolean' ? {
'test': /\.(js|mjs|jsx|ts|tsx)$/,
'enforce': 'pre',
'use': [
{
'options': {
'formatter': require('eslint-friendly-formatter'),
'eslintPath': require.resolve('eslint'),
// @remove-on-eject-begin
'baseConfig': {
'extends': [require.resolve('eslint-config-spinacia-app')],
},
'ignore': false,
'useEslintrc': false,
// @remove-on-eject-end
'fix': true
},
'loader': require.resolve('eslint-loader'),
},
],
'include': [paths.appSrc, paths.appBuild]
} : {},
{
'test': /\.(js|mjs|jsx|ts|tsx)?$/,
'loader': 'babel-loader',
'include': [paths.appSrc, paths.appBuild],
'options': {
'customize': require.resolve('./babel/webpack-overrides.js'),
'babelrc': false,
'compact': false,
'presets': [require.resolve('./babel/preset.js')],
// Make sure we have a unique cache identifier, erring on the
// side of caution.
// We remove this when the user ejects because the default
// is sane and uses Babel options. Instead of options, we use
// the react-scripts and babel-preset-react-app versions.
'cacheIdentifier': getCacheIdentifier(
'production',
[
'babel-plugin-named-asset-import',
'spinacia-script',
]
),
'plugins': [
[
require.resolve('babel-plugin-import'),
{
'libraryName': 'antd-mobile',
'style': 'css'
}
],
[
require.resolve('babel-plugin-named-asset-import'),
{
'loaderMap': {
'svg': {
'ReactComponent': '@svgr/webpack?-svgo,+ref![path]',
},
},
},
],
],
'cacheDirectory': true
}
},
{
'test': /\.(le|c)ss$/,
'use': [
{
'loader': MiniCssExtractPlugin.loader,
'options': {
// only enable hot in development
'hmr': process.env.NODE_ENV === 'development',
// if hmr does not work, this is a forceful method.
'reloadAll': true,
'publicPath': '../../'
}
},
'css-loader',
postcssOption,
'less-loader'
]
},
{
'test': /\.(ttf|eot|svg|woff|woff2)(\?.+)?$/,
'loader': 'file-loader',
'options': {
'name': '[name].[contenthash:8].[ext]',
'outputPath': 'static/media/',
'publicPath': paths.appMedia
}
},
{
'test': /\.(jpe?g|png|gif)(\?.+)?$/,
'loader': 'url-loader',
'options': {
'limit': 10000,
'name': '[name].[contenthash:8].[ext]',
'outputPath': 'static/media/',
'publicPath': paths.appMedia
}
},
{
'test': /\.md$/,
'loader': 'raw-loader'
}
]
},
'performance': {
'hints': 'warning',
'maxEntrypointSize': 250000,
'maxAssetSize': 250000
},
// Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
'node': {
'module': 'empty',
'dgram': 'empty',
'dns': 'mock',
'fs': 'empty',
'http2': 'empty',
'net': 'empty',
'tls': 'empty',
'child_process': 'empty',
},
'stats': {
'all': false,
'colors': true,
'assets': true,
'assetsSort': 'size',
'builtAt': true,
'cached': true,
'env': true,
'modules': true,
'maxModules': 0,
'performance': true,
'publicPath': true,
'version': true,
'errors': true,
'warnings': true,
// our additional options
'moduleTrace': true,
'errorDetails': true
}
};