import path from 'path'; import MiniCssExtractPlugin from 'mini-css-extract-plugin'; import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin'; import TerserPlugin from 'terser-webpack-plugin'; import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import Preprocess from 'svelte-preprocess'; import webpack from 'webpack'; import WebpackDevServer from 'webpack-dev-server'; const mode = (process.env.NODE_ENV as 'production' | 'development') || 'development'; const prod = mode === 'production'; const sveltePath = path.resolve('node_modules', 'svelte'); /** * Should source maps be generated alongside your production bundle? This will expose your raw source code, so it's * disabled by default. */ const sourceMapsInProduction = false; /** * Should we run Babel on builds? This will transpile your bundle in order to work on your target browsers (see the * `browserslist` property in your package.json), but will impact bundle size and build speed. */ const useBabel = false; /** * Should we run Babel on development builds? If set to `false`, only production builds will be transpiled. If you're * only testing in modern browsers and don't need transpiling in development, it is recommended to keep this disabled * as it will greatly speed up your builds. */ const useBabelInDevelopment = false; const config: webpack.Configuration & WebpackDevServer.Configuration = { entry: { bundle: [ './src/main.ts', ], }, resolve: { alias: { // Note: Additional aliases will be loaded automatically from `tsconfig.compilerOptions.paths` svelte: path.resolve('node_modules', 'svelte'), }, extensions: ['.mjs', '.js', '.ts', '.svelte'], mainFields: ['svelte', 'browser', 'module', 'main'], }, output: { publicPath: prod ? '' : '/build/', path: __dirname + '/public/build', filename: '[name].js', chunkFilename: '[name].[id].js', library: "kalkComponent", libraryTarget: 'window', libraryExport: 'default' }, module: { rules: [ { test: /\.svelte$/, use: { loader: 'svelte-loader-hot', options: { customElement: true, dev: !prod, emitCss: prod, hotReload: !prod, hotOptions: { // List of options and defaults: https://www.npmjs.com/package/svelte-loader-hot#usage noPreserveState: false, optimistic: true, }, preprocess: Preprocess({ scss: true, postcss: { plugins: [require('autoprefixer')], }, }), }, }, }, { test: /\.(scss|sass)$/, use: [ { loader: MiniCssExtractPlugin.loader, options: { hmr: !prod, sourceMap: !prod || sourceMapsInProduction, }, }, 'css-loader', { loader: 'postcss-loader', options: { plugins: [require('autoprefixer')], }, }, 'sass-loader', ], }, { test: /\.css$/, use: [ { loader: MiniCssExtractPlugin.loader, options: { hmr: !prod, sourceMap: !prod || sourceMapsInProduction, }, }, 'css-loader', ], }, { test: /\.ts$/, use: 'ts-loader', exclude: /node_modules/, }, ], }, devServer: { hot: true, stats: 'minimal', contentBase: 'public', watchContentBase: true, }, mode, plugins: [ new MiniCssExtractPlugin({ filename: '[name].css', }), ], optimization: { minimizer: [], }, devtool: prod && !sourceMapsInProduction ? false : 'source-map', }; // Load path mapping from tsconfig const tsconfigPath = path.resolve(__dirname, 'tsconfig.json'); const tsconfig = require('fs').existsSync(tsconfigPath) ? require(tsconfigPath) : {}; if ('compilerOptions' in tsconfig && 'paths' in tsconfig.compilerOptions) { const aliases = tsconfig.compilerOptions.paths; for (const alias in aliases) { const paths = aliases[alias].map((p: string) => path.resolve(__dirname, p)); // Our tsconfig uses glob path formats, whereas webpack just wants directories // We'll need to transform the glob format into a format acceptable to webpack const wpAlias = alias.replace(/(\\|\/)\*$/, ''); const wpPaths = paths.map((p: string) => p.replace(/(\\|\/)\*$/, '')); if (!(wpAlias in config.resolve.alias) && wpPaths.length) { config.resolve.alias[wpAlias] = wpPaths.length > 1 ? wpPaths : wpPaths[0]; } } } // These options should only apply to production builds if (prod) { // Clean the build directory for production builds config.plugins.push(new CleanWebpackPlugin()); // Minify CSS config.optimization.minimizer.push( new OptimizeCSSAssetsPlugin({ cssProcessorOptions: { map: sourceMapsInProduction ? { inline: false, annotation: true, } : false, }, cssProcessorPluginOptions: { preset: [ 'default', { discardComments: { removeAll: !sourceMapsInProduction, }, }, ], }, }) ); // Minify and treeshake JS config.optimization.minimizer.push( new TerserPlugin({ sourceMap: sourceMapsInProduction, extractComments: false, }) ); } // Add babel if enabled if (useBabel && (prod || useBabelInDevelopment)) { config.module.rules.unshift({ test: /\.(?:svelte|m?js)$/, include: [path.resolve(__dirname, 'src'), path.dirname(sveltePath)], use: { loader: 'babel-loader', options: { sourceType: 'unambiguous', presets: ['@babel/preset-env'], plugins: ['@babel/plugin-transform-runtime'], }, }, }); } export default config;