const path = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') const TerserPlugin = require('terser-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin') const utils = require('./utils') const { VueLoaderPlugin } = require('vue-loader') const merge = require('webpack-merge') const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') const portfinder = require('portfinder') const CopyWebpackPlugin = require('copy-webpack-plugin') const webpack = require('webpack') const { versionWriter, sitemapWriter } = require('./file-writer') const isProd = process.env.NODE_ENV === 'production' let outputConfig sitemapWriter() versionWriter() const webpackConf = { mode: isProd ? 'production' : 'development', context: path.resolve(__dirname, '../'), entry: { app: './main.js' }, module: { rules: [ { test: /\.vue$/, loader: 'vue-loader' }, { test: /\.md$/, use: [ { loader: 'vue-loader', options: { compilerOptions: { preserveWhitespace: false } } }, { loader: path.resolve(__dirname, './md-loader.js') } ] }, { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, { test: /\.yml$/, loader: 'yml-loader' }, { test: /\.css$/, use: utils.cssLoader('css-loader', 'postcss-loader') }, { test: /\.scss$/, use: utils.cssLoader('css-loader', 'postcss-loader', 'sass-loader') }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', options: { limit: 20000, name: utils.assetsPath('img/[name].[hash:8].[ext]') } }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: utils.assetsPath('fonts/[name].[ext]') } } ] }, devtool: isProd ? false : 'cheap-module-eval-source-map', resolve: { extensions: ['.js', '.vue', '.json', '.md', '.xml'], alias: { vue$: 'vue/dist/vue.esm.js' } }, stats: { children: false, modules: false, entrypoints: false }, plugins: [ new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(isProd ? 'prod' : 'dev') }), new VueLoaderPlugin(), new HtmlWebpackPlugin({ filename: isProd ? path.resolve(__dirname, '../dist/index.html') : 'index.html', template: path.resolve(__dirname, '../index.html'), favicon: path.resolve(__dirname, '../favicon.ico') }), new CopyWebpackPlugin([ { from: path.resolve(__dirname, '../public'), to: utils.assetsPath('public'), toType: 'dir', ignore: ['.DS_Store'] }, { from: path.resolve(__dirname, '../sitemap.xml'), to: utils.assetsPath('../sitemap.xml') } ]) ] } if (!isProd) { const devWebpackConf = merge(webpackConf, { devServer: { clientLogLevel: 'warning', historyApiFallback: { rewrites: [{ from: /.*/, to: 'index.html' }] }, hot: true, contentBase: false, compress: true, port: 8070, overlay: { warnings: false, errors: true }, open: true, quiet: true, disableHostCheck: true }, plugins: [new webpack.HotModuleReplacementPlugin()] }) outputConfig = new Promise((resolve, reject) => { portfinder.basePort = 8070 portfinder.getPort((err, port) => { if (err) { reject(err) } else { process.env.PORT = port devWebpackConf.devServer.port = port devWebpackConf.plugins.push(new FriendlyErrorsPlugin()) resolve(devWebpackConf) } }) }) } else { outputConfig = merge(webpackConf, { output: { publicPath: './', path: path.resolve(__dirname, '../dist'), filename: utils.assetsPath('js/[name].[chunkhash].js'), chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') }, optimization: { minimizer: [ new TerserPlugin({ cache: true, parallel: true }), new webpack.optimize.ModuleConcatenationPlugin(), new OptimizeCSSAssetsPlugin() ] }, plugins: [ new MiniCssExtractPlugin({ filename: utils.assetsPath('css/[name].[contenthash:8].css'), chunkFilename: utils.assetsPath('css/[name].[contenthash:8].css') }) ] }) } module.exports = outputConfig