EP.pleiadi
EP.pleiadi

Reputation: 1

Django CMS with Vite bundler instead of Webpack

I am the maintainer of a Django (with Django CMS) project, and I use Webpack to bundle all static files and templates into a dist folder. I am trying to migrate to Vite, as I read that it offers better performance than Webpack and requires fewer components to work.

this is my webpack.conf.js file:

const path = require('path');
const chalk = require('chalk');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const glob = require("glob");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const pkg = require('./package.json');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserPlugin = require("terser-webpack-plugin");
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const { defaultMinimizerOptions } = require("html-loader");

// Ignore node modules and all js files in root project
const excludedBase = ['node_modules/**', '*.js', 'dist/**']; // exclude node_modules, js into the root of prj, dist folder
// Ignored django apps
const excludedApps = [
  '**/admin/**',
  'our_content/**',
  'our_cms_plugins/base_cms_plugin/**',
  'our_composer/templates/our_composer/**',
  '**/default_style.html',                      // managed from html-webpack-plugins
  'themes/static/themes/js/main.js',            // must be the first file
  'themes/static/themes/js/components/**',      // only imported components should be included in bundle
  'themes/static/themes/css/compiled/**',       // manual import for PDF
];

const excludedPaths = excludedBase.concat(excludedApps);
const ENV_CONF = {
  PRODUCTION: 'production',
  DEV: 'development'
};

let loadEntries = (env, argv) => {
  let formattedPaths = ['./themes/static/themes/js/main.js'];
  let jsPaths = glob.sync("**/*.js", {ignore: excludedPaths});

  jsPaths.map(obj => {
    formattedPaths.push(`./${obj}`);
  });

  console.log(`
    ${chalk.black.bgBlue('DEPENDENCIES')}  
    ${chalk.blue(`${Object.keys(pkg.dependencies).join('\n')}`)}  
    
    ${chalk.black.bgBlue('WEBPACK ENTRIES')}
    ${chalk.blue(`${jsPaths.join('\n')}`)}
`);

  // Also copy minified templates into dist
  if (argv.mode === ENV_CONF.PRODUCTION) {
    let htmlPaths = glob.sync("**/*.html", {ignore: excludedPaths});
    htmlPaths.map(obj => {
      formattedPaths.push(`./${obj}`);
    });
  }

  return {
    //main: './themes/static/themes/js/main.js',
    app: formattedPaths
  };

};


module.exports = (env, argv) => {
  const devMode = argv.mode === ENV_CONF.DEV;
  const showReport = process.env.SHOW_REPORT ? true : false;

  return {
    entry: () => new Promise((resolve) => resolve(loadEntries(env, argv))),
    devtool: devMode ? 'eval-source-map': false,
    cache: {
      type: 'filesystem',
      compression: 'gzip',
    },
    module: {
      rules: [
        {
          test: /\.html$/,
          use: [
            {
              loader: 'file-loader',
              options: {
                name(file) {
                  let folderTemplates = 'templates';
                  let startIndex = file.search(folderTemplates);
                  startIndex += folderTemplates.length + 1;

                  return file.substr(startIndex);
                },
                outputPath: 'templates/',
                publicPath: 'templates'
              }
            },
            {
              loader: "extract-loader",
            },
            {
              loader: 'html-loader',
              options: {
                minimize: {
                  ...defaultMinimizerOptions,
                  minifyCSS: false
                },
                sources: {
                  list: [
                    {
                      tag: "source",
                      attribute: "srcset",
                      type: "srcset",
                      filter: () => false,
                    },
                  ]
                },
              }
            }
          ],
          exclude: [
            path.resolve(__dirname, 'themes/templates/themes/style/default_style.html'),
            // path.resolve(__dirname, 'network/templates/network/dealers_locator/index.html'),
          ]
        },
        {
          test: /\.css$/,
          use: [
            'style-loader',
            'css-loader'
          ]
        },
        {
          test: /\.scss$/,
          use: [
            // 'vue-style-loader',
            {
              loader: MiniCssExtractPlugin.loader,
              options: {
                  publicPath: ''
              }
            },
            "cache-loader",
            "css-loader",
            "postcss-loader",
            {
              loader: 'resolve-url-loader',
              options: {}
            },
            {
              loader: 'sass-loader',
              options: {
                implementation: require('sass-embedded'),
                sourceMap: true,
                sassOptions: {
                  quietDeps: true
                },
              }
            },
          ]
        },
        {
          test: /\.js$/,
          //exclude: /node_modules/,
          //exclude: /node_modules\/(?!(aos|foundation-sites|handlebars|imagesloaded|isotope-layout|jquery|jquery-match-height|lightcase|lodash|popper.js|slick-carousel|vis)\/).*/,
          exclude: file => (
            /node_modules/.test(file) && !/\.vue\.js/.test(file) && /node_modules\/(?!(dom7|ssr-window|swiper|vanilla-lazyload|aos|foundation-sites|jquery|jquery-match-height)\/).*/.test(file)
          ),
          use: [
            {
              loader: 'cache-loader'
            },
            {
              loader: 'thread-loader'
            },
            {
              loader: "babel-loader?cacheDirectory=true",
              options: {
                cacheCompression: false,
                cacheDirectory: true,
              },
            }
          ]
        },
        {
          test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
          type: 'asset/resource'
        },
        {
              test: /\.(jpg|png|svg|gif)$/,
              type: 'asset/resource',
        },
        { // Swiper specific: declaring no sideEffects in order to shake the tree
          test: /swiper\.esm\.js/,
          sideEffects: false
        }
      ]
    },
    plugins: [
      // new BundleAnalyzerPlugin(),
      new MiniCssExtractPlugin({
        // Options similar to the same options in webpackOptions.output
        // both options are optional
        filename: devMode ? '[name].css' : '[name].[chunkhash].css',
        chunkFilename: devMode ? '[name].css' : '[name].[chunkhash].css'
      }),
      new OptimizeCssAssetsPlugin({
        assetNameRegExp: /\.css$/g,
        cssProcessor: require('cssnano'),
        cssProcessorOptions: {
          map: {
            inline: false,
            annotation: true,
          }
        },
        cssProcessorPluginOptions: {
         preset: ['advanced', {zindex: false, discardComments: {removeAll: false}}],
        },
        canPrint: true
      }),
      new HtmlWebpackPlugin({
        filename: 'templates/themes/style/default_style.html',
        template: 'themes/templates/themes/style/default_style.html',
        inject: 'body',
        excludeChunks: [
            'dealerslocator',
        ]
      }),
      // new HtmlWebpackPlugin({
      //     filename: 'templates/network/dealers_locator/index.html',
      //     template: 'network/templates/network/dealers_locator/index.html',
      //     inject: false,
      //     chunks: ['dealerslocator']
      // }),
      new CleanWebpackPlugin(),
      // new webpack.ProvidePlugin({
      //   //$: 'jquery',
      //   jQuery: 'jquery'
      // })
    ].concat(showReport ? [new BundleAnalyzerPlugin()] : []),

    optimization: {
      minimize: true,
      minimizer: [new TerserPlugin({})],
      splitChunks: {
        cacheGroups: {
          commons: {
            test: /[\\/]node_modules[\\/]/,
            name: 'vendors',
            chunks: 'all',
          },
        },
      }
    },
    devServer: {
      // host: '0.0.0.0',
      hot: false,
      compress: true,
      // publicPath: 'http://localhost:8000/static',
      static: {
        directory: path.join(__dirname, 'dist'),
      },
      port: 9002,
      proxy: {
        '*': 'http://127.0.0.1:8000'
      }
    },
    output: {
      publicPath: '/static/',
      clean: true,
      filename: argv.mode !== ENV_CONF.PRODUCTION ? '[name].bundle.js' : '[name].[contenthash].js',
      chunkFilename: argv.mode !== ENV_CONF.PRODUCTION ? '[name].bundle.js' : '[name].[contenthash].js',
      assetModuleFilename: 'static/[contenthash][ext][query]'
    },
  };
};

I am trying to migrate this logic to a vite.config.js file, but it doesn't work:

import { defineConfig } from 'vite';
import path from 'path';
import { createHtmlPlugin } from 'vite-plugin-html';
import { visualizer } from 'rollup-plugin-visualizer';

export default defineConfig(({ mode }) => {
  const isProduction = mode === 'production';

  return {
    plugins: [
      // Plugin per la gestione dei template HTML
      createHtmlPlugin({
      minify: true, // Puoi abilitare o disabilitare la minificazione
      entry: 'themes/templates/themes/style/default_style.html', // Punto di ingresso
      template: 'themes/templates/themes/style/default_style.html',
      inject: {
        data: {
          injectTo: 'body',
        },
      },
      excludeChunks: ['dealerslocator'], // Questo va implementato manualmente se necessario
    }),
    ],
    css: {
      preprocessorOptions: {
        scss: {
          additionalData: `@import "foundation-sites/scss/foundation";` // Aggiungi qui se vuoi un import globale
        }
      }
    },
    build: {
      rollupOptions: {
        input: 'themes/static/themes/js/main.js', // Specifica il punto di ingresso corretto
        output: {
          assetFileNames: (assetInfo) => {
            if (assetInfo.name.endsWith('.css')) {
              return 'static/[name].[hash][extname]';
            }
            return 'static/[name].[hash][extname]';
          },
          chunkFileNames: 'static/[name].[hash].js',
          entryFileNames: 'templates/themes/style/default_style.html',
          // Output configuration for HTML files
          // Ensuring HTML files are placed correctly
          format: 'es',
          dir: path.resolve(__dirname, 'dist/templates'), // Directory for HTML and assets
        },
      },
      chunkSizeWarningLimit: 500, // Limite di dimensione per i chunk
      sourcemap: !isProduction, // Abilita le source map in modalità sviluppo
    },
    server: {
      proxy: {
        '/api': 'http://localhost:8003',
      },
      port: 9003,
    },
    resolve: {
    alias: {
      '~foundation-sites': path.resolve(__dirname, 'node_modules/foundation-sites'),
      '~swiper': path.resolve(__dirname, 'node_modules/swiper'),
    },
  },
  };
});

Could someone help me? I would be really grateful.

If someone could provide me with their solution, I would be really grateful.

Upvotes: 0

Views: 87

Answers (0)

Related Questions