webpack-papa-script
Version:
A frontend projects solution
385 lines (364 loc) • 9.75 kB
JavaScript
const path = require('path');
const { fromJS } = require('immutable');
const webpack = require('webpack');
const proxy = require('http-proxy-middleware');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const SriPlugin = require('webpack-subresource-integrity');
const T = require('./util/tpl');
const webPath = require('./util/webPath');
const dc = require('./config');
const Set = require('./webpack.set.entry');
const IsPro = Set.deployType === dc.getProDeployName();
const IsTest = Set.deployType === dc.getDevDeployName();
const IsProduction = process.env.NODE_ENV === 'production';
let CSS_Module_Loader_Pargram, CSS_SourceMap, imgCompress, publicPath;
const vendorLoc = Set.DUAN.length < 2 ? Set.DUAN[0] : 'vendors';
const fileNameHash = IsProduction ? '_[hash:8]' : '';
const kiss_ie8 = dc.kiss_ie8; // Same name as uglify's IE8 option. Turn this on to enable HMR.
const strSep = path.sep.replace(/(\/|\\)/g, '\\$1');
const rootDir = path.join(process.cwd(), './src');
const aProxy = dc.proxy
? Array.isArray(dc.proxy)
? dc.proxy
: [dc.proxy]
: [];
const plugins = [
/*'syntax-flow',*/
new ExtractTextPlugin({
filename: `[name]/main${fileNameHash}.css`,
allChunks: true
}),
//@手动把公共的集中到这里
new webpack.optimize.CommonsChunkPlugin({
name: 'vendors',
filename: `${vendorLoc}/vendors${fileNameHash}.js`,
minChunks: 3
}),
/* new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery",
"window.Zepto":"jquery"
}),*/
new SriPlugin({
hashFuncNames: ['sha512'],
enabled: process.env.NODE_ENV === 'production' && dc.defPlugin.sri
}),
...Set.htmlDeclare
];
/* plugin define */
/* istanbul ignore else */
if (IsProduction) {
//console.log('目前编译生产环境');
plugins.push(
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
...dc.customPlugin.production
);
if (!IsTest && dc.defPlugin.uglifyJs) {
plugins.push(
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
screw_ie8: !kiss_ie8
},
mangle: { screw_ie8: !kiss_ie8 },
output: { screw_ie8: !kiss_ie8 }
})
);
}
CSS_Module_Loader_Pargram =
'?modules&importLoaders=1&localIdentName=[hash:6]';
CSS_SourceMap = '';
imgCompress = '!image-webpack-loader';
if (IsTest) {
publicPath = T(dc.remotePath, { target: Set.module });
} else {
publicPath = (IsPro ? dc.cdnDomain : '') + webPath.join(
T(dc.remotePath, {
target: Set.module
})
);
}
}
// not IsProduction
else {
//console.log('目前编译开发环境');
plugins.push(new webpack.HotModuleReplacementPlugin(),...dc.customPlugin.development);
CSS_Module_Loader_Pargram =
'?modules&importLoaders=1&localIdentName=[path]__[name]__[local]__[hash:3]';
CSS_SourceMap = '?sourceMap';
imgCompress = '';
publicPath = T(dc.remotePath, { target: Set.module });
}
/* loader config define */
const postcssConf = {
loader: 'postcss-loader',
options: {
ident: 'postcss',
sourceMap: true,
plugins: loader => [
require('autoprefixer')()
// 不能使用cssnano。require.ensure时,需要ExtractTextPlugin的allChunks: true,fallback 走style-loader, 导致cssnano改keyFrame名字时重复了。。
//require('cssnano')()
]
}
};
const htmlLoaderOpt = {
minimize: IsProduction,
ignoreCustomFragments: [/{{.*?}}/],
root: rootDir,
attrs: ['img:src', 'img:data-src', 'link:href']
};
const babelPlugin = [
'@babel/plugin-transform-runtime',
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-transform-object-assign'
//'@babel/plugin-syntax-dynamic-import'
];
const picUrlLoaderOpt = {
loader: 'file-loader',
options: {
name: 'img/[name]_[hash:5].[ext]' /*+ imgCompress*/
}
};
/***** (⁎⁍̴̛ᴗ⁍̴̛⁎) *****/
const webpackConfig = {
context: path.resolve('./'),
entry: Object.assign({}, Set.entry),
output: {
path: path.resolve(Set.outputDir, Set.module),
filename: `[name]/bundle${fileNameHash}.js`,
publicPath,
chunkFilename: `${vendorLoc}/chunk_[name]${fileNameHash}.js`,
crossOriginLoading: 'anonymous'
},
resolve: {
modules: ['node_modules', rootDir],
extensions: ['.js', '.jsx'],
alias: {}
},
plugins,
module: {
rules: [
//#region js,sw
{
test: /\.js$/,
exclude: /(node_modules|bower_components|sw.js)/,
//include:/node_modules\/fow-encrypt/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: [
'@babel/preset-env' /*'@babel/preset-stage-0' ie8 will crash*/
],
plugins: babelPlugin
}
}
},
{
test: /sw\.js$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name]_[hash:8].[ext]'
}
}
]
},
{
test: /manifest\.json$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]'
}
}
]
},
{
test: /\.jsx$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: [
'@babel/preset-env',
'@babel/preset-react' /*'@babel/preset-stage-0' ie8 will crash*/
],
plugins: babelPlugin
}
}
},
IsProduction && kiss_ie8
? {
test: /\.jsx?$/,
enforce: 'post',
loader: 'es3ify-loader'
}
: {},
//#endregion
//#region css
{
test: /\.css$/,
exclude: /http/,
use: !IsProduction
? ['style-loader', 'css-loader', 'resolve-url-loader']
: /*[MiniCssExtractPlugin.loader, 'css-loader', 'resolve-url-loader']*/
ExtractTextPlugin.extract({
fallback: ['style-loader'],
use: ['css-loader', postcssConf, 'resolve-url-loader']
})
},
{
test: /\.scss$/,
exclude: /http/,
use: !IsProduction
? ['style-loader', 'css-loader', 'resolve-url-loader', 'sass-loader']
: /*[MiniCssExtractPlugin.loader, 'css-loader', 'resolve-url-loader', 'sass-loader']*/
ExtractTextPlugin.extract({
fallback: ['style-loader'],
use: [
'css-loader',
postcssConf,
'resolve-url-loader',
'sass-loader'
]
})
},
//#endregion
//#region pic
{
test: /\.(png|gif)$/,
exclude: /http|iso/,
use: [
{
loader: 'url-loader',
options: {
limit: 4096,
name: 'img/[name]_[hash:5].[ext]' /*+ imgCompress*/
}
}
]
},
{
test: /\.iso.(png|gif)$/,
exclude: /http/,
use: [picUrlLoaderOpt]
},
{
test: /\.jpe?g|svg$/,
exclude: /http/,
use: [picUrlLoaderOpt]
},
//#endregion
//#region tpl
{
test: /\.handlebars$/,
exclude: new RegExp(`resource${strSep}html`),
use: [
{
loader: 'handlebars-loader',
options: { debug: false, helperDirs: [...Set.helperDirs] }
},
{
loader: 'extract-loader'
},
{
loader: 'html-loader',
options: htmlLoaderOpt
}
]
},
{
test: new RegExp(`resource${strSep}html${strSep}.+\\.handlebars$`),
use: [
{
loader: 'handlebars-loader'
}
]
},
{
test: /\.tmpl$/,
use: {
loader: 'html-loader',
options: htmlLoaderOpt
}
},
//为了解决html修改后不会自动reload的问题
{
test: /index.html$/,
use: {
loader: 'html-loader'
}
},
//#endregion
{
test: /\.(woff|woff2|eot|ttf|pdf)$/,
exclude: /http/,
use: [
{
loader: 'url-loader',
options: {
limit: 1,
name: '/font/[name]_[hash:5].[ext]'
}
}
]
}
]
},
devServer: {
contentBase: path.join(process.cwd(), dc.serveContentBase),
publicPath,
hot: true,
inline: true,
port: dc.servePort,
host: 'localhost',
quiet: !!process.env._mocha_test,
before(app) {
// 代理筛选
for (let proxyConf of aProxy) {
let {filterPathname} = proxyConf;
delete proxyConf.filterPathname;
app.get(filterPathname, proxy(proxyConf));
}
},
allowedHosts: ['.'] // allow all
}
/*imageWebpackLoader: {
mozjpeg: {
quality: 100
},
pngquant: {
quality: "60-100",
speed: 4
},
svgo: {
plugins: [
{
removeViewBox: false
}, {
removeEmptyAttrs: false
}
]
}
}*/
};
if (process.env.NODE_ENV !== 'production') {
webpackConfig.devtool = '#inline-source-map';
} else if (IsTest) {
webpackConfig.devtool = 'eval';
}
//fromJS toJS
const mergedConfig = fromJS(webpackConfig)
.mergeDeep(dc.webpackConfig)
.toJS();
module.exports = mergedConfig;