require('dotenv').config(); const path = require('path'); const VueLoaderPlugin = require('vue-loader/lib/plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const DotenvPlugin = require('dotenv-webpack'); const merge = require('webpack-merge'); const targetDir = path.normalize(path.join(__dirname, 'dist')); if (! process.env.NODE_ENV) { console.error('Please set NODE_ENV'); process.exit(1); } const babelOpts = { presets: [ '@babel/preset-env', ], }; const tsconfig = require('./tsconfig.json'); const pathAliases = Object.entries(tsconfig.compilerOptions.paths || []).reduce((aliases, pair) => { let alias = pair[0]; if (alias.endsWith('/*')) alias = alias.slice(0, -2); let aliasPath = pair[1][0]; if (aliasPath.endsWith('/*')) aliasPath = aliasPath.slice(0, -2); aliases[alias] = path.resolve(__dirname, aliasPath); return aliases; }, {}); let config = { entry: './src/main.ts', output: { filename: '[name].[hash].js', path: targetDir, publicPath: '/', }, module: { rules: [ // Vue / Babel / Typescript { test: /\.vue$/, use: ["vue-loader"], }, { test: /\.tsx?$/, exclude: /node_modules/, use: [ { loader: 'babel-loader', options: babelOpts, }, { loader: 'ts-loader', options: { appendTsSuffixTo: [/\.vue$/], }, }, ], }, { test: /\.m?js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: babelOpts, }, }, { test: /\.js$/, use: ["source-map-loader"], enforce: "pre", }, // Stylesheets { test: /\.p?css$/, use: [ "vue-style-loader", { loader: "css-loader", options: { importLoaders: 1, }, }, { loader: "postcss-loader", options: { ident: "postcss", plugins: loader => { const plugins = [ require('postcss-import')({ resolve(id, base, options) { // Since WebStorm doesn't resolve imports from node_modules without a tilde (~) prefix, // strip the tilde here to get the best of both worlds (webstorm support + postcss-import support) if (id[0] === '~') id = id.slice(1); // Call the original resolver after stripping the tilde return require('postcss-import/lib/resolve-id')(id, base, options); }, }), require('postcss-nesting')(), require('tailwindcss')(), ]; if (process.env.NODE_ENV === "production") { plugins.push( require('postcss-preset-env')(), require('cssnano')(), ); } return plugins; }, }, }, ], }, // Images/files { test: /\.(png|jpg)$/i, use: { loader: "file-loader", options: { name: "[name]-[hash].[ext]", }, }, }, // HTML { test: /\.html$/, use: [ { loader: "html-loader", options: { root: path.resolve(__dirname, 'src'), attrs: ['img:src', 'link:href'], ...(process.env.NODE_ENV === 'production' && { minimize: true, removeComments: true, collapseWhitespace: true, }), }, }, ], }, ], }, plugins: [ new VueLoaderPlugin(), new HtmlWebpackPlugin({ template: 'src/index.html', files: { "css": ["./src/style/initial.pcss"], "js": ["./src/main.ts"], }, }), new DotenvPlugin(), ], resolve: { extensions: ['.ts', '.tsx', '.js', '.mjs', '.vue'], alias: pathAliases, }, }; if (process.env.NODE_ENV === 'production') { config = merge(config, { mode: 'production', devtool: 'source-map', }); } else { config = merge(config, { mode: 'development', devtool: 'eval', devServer: { ...(process.env.DEV_HOST ? { host: process.env.DEV_HOST } : undefined), historyApiFallback: true, port: 1234, }, }); } module.exports = config;