Automatically define vite entrypoints based on paths provided in a drupal asset library

Created on 10 February 2023, almost 2 years ago

Problem/Motivation

Currently, asset entrypoints have to be defined in two places:

  • drupal asset library definition (theme/module .libraries.yml)
  • vite config

It would be nice to get entrypoints in vite config automatically from asset library definition. Wihtout the need to manually configure them on the vite side.

Proposed resolution

Create vite plugin that will parse drupal asset library definition (.libaries.yml) and automatically provide entrypoints based on paths configured in asset library definition.

✨ Feature request
Status

Active

Version

1.0

Component

Code

Created by

πŸ‡΅πŸ‡±Poland wotnak

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @wotnak
  • πŸ‡ΊπŸ‡ΈUnited States mortona2k Seattle

    I think it's easier to go the other way, and have Drupal use manifest.json to define the assets. Vite adds them to the entry chunk's css property.

    It looks like the code is trying to add these bundled files, but only gets them when vite has a certain setup. I added a related issue with a patch.

  • πŸ‡¦πŸ‡ΊAustralia darvanen Sydney, Australia

    I agree with #2. Suggest this issue be closed as "won't fix"

  • πŸ‡¦πŸ‡ΊAustralia darvanen Sydney, Australia

    .... so I've come full circle on this.

    Not sure it needs a vite plugin, but here's my vite config at the moment that basically does what's in the IS:

    import { defineConfig } from 'vite'
    import react from '@vitejs/plugin-react'
    import { globSync } from 'glob'
    import yaml from 'js-yaml'
    import { readFileSync } from 'fs'
    
    export default defineConfig(({ mode }) => {
      const env = mode === 'production' ? '"production"' : '"development"'
    
      return {
        build: {
          cssCodeSplit: true,
          manifest: true,
          rollupOptions: {
            external: '[Drupal, once]',
            input: getInputs()
          },
        },
        css: {
          devSourcemap: true,
          preprocessorOptions: {
            scss: {
              api: 'modern',
              quietDeps: true,
            },
          },
        },
        define: { 'process.env.NODE_ENV': env },
        plugins: [react],
        scss: {
          api: 'modern',
        },
      }
    
      function getInputs() {
        const inputs = []
    
        // Use glob to find all relevant YAML files
        const libraryFilePaths = globSync([
          './app/modules/custom/**/*.libraries.yml',
          './app/themes/custom/**/*.libraries.yml',
        ])
    
        // Iterate through each library file path
        for (const filePath of libraryFilePaths) {
          try {
            // Read the file contents
            const fileContents = readFileSync(filePath, 'utf8')
    
            // Parse the YAML contents
            const libraryConfigs = yaml.load(fileContents)
    
            // Iterate through each top-level library configuration
            for (const [libraryName, libraryConfig] of Object.entries(
              libraryConfigs,
            )) {
              // Check if the library configuration has a 'vite' key
              if (libraryConfig.vite) {
                // Process CSS sources
                if (libraryConfig.css) {
                  const cssSources = Object.keys(libraryConfig.css)
                    .filter(key => typeof libraryConfig.css[key] === 'object')
                    .flatMap(key =>
                      Object.keys(libraryConfig.css[key])
                        .filter(
                          subKey =>
                            typeof libraryConfig.css[key][subKey] === 'object',
                        )
                        .map(subKey => subKey),
                    )
    
                  inputs.push(...cssSources)
                }
    
                // Process JS sources
                if (libraryConfig.js) {
                  const jsSources = Object.keys(libraryConfig.js)
                    .filter(key => typeof libraryConfig.js[key] === 'object')
                    .map(key => key)
    
                  inputs.push(...jsSources)
                }
              }
            }
          } catch (error) {
            console.error(`Error processing library file ${filePath}:`, error)
          }
        }
    
        return inputs
      }
    })
    
  • πŸ‡ΊπŸ‡ΈUnited States mortona2k Seattle

    So this fetches all custom module and theme libraries files, then uses all defined paths in there?

    Looks like this will help with including things out side of your theme in the vite build.

  • πŸ‡¦πŸ‡ΊAustralia darvanen Sydney, Australia

    Yes, that is what it is does and what it is for. I think it might help with the #frontend-bundler-initiative I've been working on but it needs more work.

    Specifically it needs to respect vite: false on individual assets, and it would be really nice if I could find a way to reset the inputs when those library files are altered (or added/removed).

    I have been using https://www.npmjs.com/package/vite-plugin-watch-and-run to run drush cr when twig files are added/removed, I might be able to find something in there.

Production build 0.71.5 2024