| const path = require("path"); |
| const { CleanWebpackPlugin } = require("clean-webpack-plugin"); |
| const CopyPlugin = require("copy-webpack-plugin"); |
| const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; |
| const Handlebars = require("handlebars"); |
| const fs = require("fs"); |
| const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin"); |
| const HtmlMinimizerPlugin = require("html-minimizer-webpack-plugin"); |
|
|
|
|
| const FRAGMENTS_PATH = "src/fragments"; |
|
|
| |
| const loadFragmentsMap = (() => { |
| let cachedFragments = null; |
| return async () => { |
| if (cachedFragments === null) { |
| cachedFragments = {}; |
| const walkDir = async (dir, basePath = '') => { |
| const files = fs.readdirSync(dir); |
| await Promise.all(files.map(async file => { |
| const filePath = path.join(dir, file); |
| const relativePath = path.join(basePath, file); |
| if (fs.statSync(filePath).isDirectory()) { |
| await walkDir(filePath, relativePath); |
| } else { |
| |
| const nameWithoutExt = relativePath.replace(/\.html$/, ''); |
| const dottedPath = 'fragment-' + nameWithoutExt.replace(/\\/g, '-').replace(/\//g, '-').replace(/\./g, '-'); |
| const content = fs.readFileSync(filePath, "utf8"); |
| |
| const minifiedRes = await HtmlMinimizerPlugin.swcMinifyFragment({"tmp.html": content}) |
| if (minifiedRes.errors) { |
| console.error(minifiedRes.errors) |
| } |
| const minifiedContent = minifiedRes.code; |
| cachedFragments[dottedPath] = minifiedContent; |
| } |
| })); |
| }; |
| await walkDir(FRAGMENTS_PATH); |
| } |
| return cachedFragments; |
| }; |
| })(); |
|
|
| const transformHandlebars = async (data, path) => { |
| const fragments = await loadFragmentsMap(); |
| console.log(`Available fragments: ${Object.keys(fragments).join(', ')}`); |
| |
| const template = Handlebars.compile(data.toString('utf8')); |
| const html = template(fragments); |
| return html; |
| }; |
|
|
| module.exports = { |
| entry: { |
| distill: "./src/distill.js", |
| main: "./src/index.js", |
| }, |
| output: { |
| filename: "[name].bundle.js", |
| path: path.resolve(__dirname, "dist"), |
| }, |
| module: { |
| rules: [ |
| { test: /\.css$/, use: ["style-loader", "css-loader"] }, |
| { |
| test: /\.(js|mjs)$/, |
| exclude: /node_modules/, |
| use: { |
| loader: "babel-loader", |
| options: { |
| presets: ["@babel/preset-env"], |
| }, |
| }, |
| }, |
| {} |
| ], |
| }, |
| plugins: [ |
| new CleanWebpackPlugin(), |
| new CopyPlugin({ |
| patterns: [ |
| { |
| from: "assets", |
| to: "assets", |
| }, |
| { from: "src/fragments/*", to: "fragments/[name].html" }, |
| { from: "src/style.css", to: "style.css" }, |
| { from: "src/bibliography.bib", to: "bibliography.bib" }, |
| { |
| from: "src/index.html", |
| to: "index.html", |
| transform: transformHandlebars, |
| }, |
| ], |
| }), |
| ], |
| devtool: process.env.NODE_ENV === 'production' ? 'source-map' : 'eval-source-map', |
| devServer: { |
| static: "./dist", |
| open: process.env.NODE_ENV !== 'production', |
| hot: process.env.NODE_ENV !== 'production', |
| }, |
| mode: process.env.NODE_ENV === 'production' ? 'production' : 'development', |
| optimization: { |
| minimizer: [ |
| |
| |
| new ImageMinimizerPlugin({ |
| minimizer: [{ |
| implementation: ImageMinimizerPlugin.sharpMinify, |
| options: { |
| encodeOptions: { |
| |
| jpeg: { |
| quality: 80 |
| }, |
| |
| png: { |
| quality: 80 |
| }, |
| |
| webp: { |
| quality: 80 |
| } |
| } |
| } |
| }, |
| { |
| implementation: ImageMinimizerPlugin.svgoMinify, |
| options: { |
| encodeOptions: { |
| multipass: true, |
| plugins: [ |
| 'preset-default', |
| ] |
| } |
| } |
| } |
| ] |
| }), |
| |
| new HtmlMinimizerPlugin({ |
| test: /fragments\/.*\.html$/i, |
| minify: HtmlMinimizerPlugin.swcMinifyFragment, |
| }) |
| ] |
| }, |
| }; |
|
|
| console.log(process.env.NODE_ENV) |