const webpack = require('webpack'); const cssnano = require('cssnano'); const pxtorem = require('postcss-pxtorem'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CleanWebpackPlugin = require('clean-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const debug = require('debug')('app:webpack:config'); const fs = require('fs'); const config = require('../config'); const paths = config.utils_paths; const { __DEV__, __PROD__ } = config.globals; function getPublicPath(path) { const publicPath = config.publicPath.substr(config.publicPath.length - 2, 1) === '/' ? config.publicPath : config.publicPath + '/'; if (path) { path = path.indexOf('/') === 0 ? path.substr(1, path.length - 1) : path; return publicPath + path; } else { return publicPath; } } function fileNameFormat(type, ext) { ext = ext || '[ext]'; return `src/[name].[${type}].${ext}`; } debug('Creating configuration.'); const webpackConfig = { name: 'client', target: 'web', cache: true, resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'], alias: { '@src': paths.client(), '@project': paths.project(), '@components': paths.components(), }, }, module: {}, stats: config.compiler_stats, }; if (config.compiler_devtool) webpackConfig.devtool = config.compiler_devtool; const APP_ENTRY = paths.client('main.js'); const devApp = [ 'webpack/hot/dev-server', `webpack-hot-middleware/client?path=${config.publicPath}__webpack_hmr`, 'react-hot-loader/patch', APP_ENTRY, ]; webpackConfig.entry = { app: __DEV__ ? devApp : [APP_ENTRY], }; webpackConfig.output = { filename: fileNameFormat(config.compiler_hash_type, 'js'), path: paths.dist(), publicPath: getPublicPath(), chunkFilename: fileNameFormat(config.compiler_hash_type, 'js'), }; function getLibPath(path) { let pach = null; try { fs.readdirSync(path).forEach(file => { if (file.indexOf('lib') === 0) { pach = file; } }); } catch (e) { console.log(e); } return pach; } if (!config.css) config.css = []; for (let i = 0; i < config.css.length; i += 1) { const script = config.css[i]; if (script.indexOf('http') !== 0) { config.css[i] = getPublicPath(script); } } if (!config.scripts) config.scripts = []; for (let i = 0; i < config.scripts.length; i += 1) { const script = config.scripts[i]; if (script.indexOf('http') !== 0) { config.scripts[i] = getPublicPath(script); } } config.scripts.push(getPublicPath(getLibPath(paths.lib()))); webpackConfig.plugins = [ new webpack.DefinePlugin(config.globals), new CleanWebpackPlugin(['*'], { root: paths.dist(), }), new webpack.ProgressPlugin(), new webpack.DllReferencePlugin({ context: paths.lib(), manifest: paths.lib('manifest.json'), extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'], }), new HtmlWebpackPlugin({ template: paths.client('index.html'), hash: false, minify: { collapseWhitespace: true, }, title: config.title, filename: 'index.html', inject: 'body', globals: Object.assign(config.globals, { keyword: config.keyword, description: config.description, scripts: config.scripts, css: config.css, }), }), new webpack.LoaderOptionsPlugin({ options: { postcss() { return [ cssnano({ autoprefixer: { add: true, browsers: ['iOS >= 7', 'Android >= 4.1'], }, discardComments: { removeAll: true, }, discardUnused: false, mergeIdents: false, reduceIdents: false, safe: true, sourcemap: true, }), pxtorem({ rootValue: 50, propWhiteList: [], }), ]; }, }, }), ]; if (__DEV__) { webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin(), new webpack.NoEmitOnErrorsPlugin()); } else { webpackConfig.plugins.push( // new webpack.optimize.CommonsChunkPlugin({ // name: ['app'], // minChunks: function (module, count) { // return module.context && module.context.indexOf('node_modules') !== -1 // } // }), new webpack.optimize.UglifyJsPlugin({ cache: true, parallel: true, }), new ExtractTextPlugin({ filename: fileNameFormat(config.compiler_hash_type, 'css'), allChunks: true, }), ); } webpackConfig.module.rules = [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: ['babel-loader', 'eslint-loader'], }, { test: /\.yml$/, use: ['json-loader', 'yaml-loader'], }, { test: /\.json$/, use: 'json-loader', }, { test: /\.(svg)(\?.*)?$/, include: paths.client(), use: { loader: 'url-loader', options: { limit: 10240, name: fileNameFormat('hash'), }, }, }, { test: /\.(png|jpe?g|gif)(\?.*)?$/, use: { loader: 'url-loader', options: { limit: 10240, name: fileNameFormat('hash'), }, }, }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, use: { loader: 'url-loader', options: { limit: 10240, name: fileNameFormat('hash'), }, }, }, ]; function loaderAnalysis(loaders) { if (__PROD__) { return ExtractTextPlugin.extract({ fallback: loaders.shift(), use: loaders, }); } return loaders; } const theme = { // 'primary-color': '#8573AD', 'brand-primary': '#6b43fe', }; webpackConfig.module.rules.push({ test: /\.css$/, use: loaderAnalysis(['style-loader', 'css-loader', 'postcss-loader']), }); webpackConfig.module.rules.push({ test: /\.less$/, use: loaderAnalysis([ 'style-loader', 'css-loader', 'postcss-loader', `less-loader?{'modifyVars':${JSON.stringify(theme)}}`, ]), }); module.exports = webpackConfig;