Skip to content

Instantly share code, notes, and snippets.

@nihalgonsalves
Last active June 24, 2021 01:40
Show Gist options
  • Save nihalgonsalves/6e6f0e8f847bc514d07136ae37564fd7 to your computer and use it in GitHub Desktop.
Save nihalgonsalves/6e6f0e8f847bc514d07136ae37564fd7 to your computer and use it in GitHub Desktop.
Vite Plugin: Custom Optimize Deps
import path from 'path'
import { build, Plugin as EsbuildPlugin } from 'esbuild'
import { PluginOption } from 'vite'
// Since plugin support for the optimizeDeps phase isn't ready yet:
// https://github.com/vitejs/vite/pull/2886
// https://github.com/vitejs/vite/pull/2991
// We can exclude the deps and then optimize them ourselves.
// In the future, this plugin can be removed, and the plugin config
// can be moved to the config directly.
const PLUGIN_NAME = 'customOptimizeDeps'
export const customOptimizeDeps = (opts: {
nodeModulesRoot: string,
includedDeps: string[],
plugins: EsbuildPlugin[],
}): PluginOption => {
const NODE_MODULES_ROOT = opts.nodeModulesRoot
const CACHE_ROOT = path.join(NODE_MODULES_ROOT, `./.vite/${PLUGIN_NAME}`)
const depsToBundleRecord: Record<string, string> = {}
return {
name: PLUGIN_NAME,
enforce: 'pre',
apply: 'serve',
configResolved: async (config) => {
const entryPoints = opts.includedDeps.map(dep => {
const packagePath = path.dirname(require.resolve(`${dep}/package.json`))
// reads the "module" field, which should point to the es module
try {
const { module } = require(`${dep}/package.json`)
const modulePath = path.join(packagePath, module)
depsToBundleRecord[dep] = modulePath.replace(
NODE_MODULES_ROOT,
CACHE_ROOT,
)
return modulePath
} catch (e) {
// silence depScan dynamic require warning
throw e
}
})
console.log(PLUGIN_NAME, {
depsToBundleRecord,
entryPoints,
})
await build({
entryPoints,
outbase: NODE_MODULES_ROOT,
outdir: CACHE_ROOT,
plugins: opts.plugins,
// original vite config
// https://github.com/vitejs/vite/blob/0dc6e37/packages/vite/src/node/optimizer/index.ts#L235-L249
bundle: true,
keepNames: config.optimizeDeps?.keepNames,
format: 'esm',
external: config.optimizeDeps?.exclude,
logLevel: 'error',
splitting: true,
sourcemap: true,
treeShaking: 'ignore-annotations',
metafile: true,
define: config.define,
})
},
resolveId: id => {
const resolved = depsToBundleRecord[id]
if (resolved) {
console.log(PLUGIN_NAME, { id, resolved })
return resolved
}
},
}
}
@carere
Copy link

carere commented Jun 18, 2021

@nihalgonsalves

Thanks a lot for your workaround 😄

I still got the problem that some built-in node utilities are not defined. (In my case it is util)
Can you provide me an example of how you would use your plugin ?

Here is my vite.config.ts:

import { defineConfig } from 'vite';
import reactRefresh from '@vitejs/plugin-react-refresh';
import tsconfigPaths from 'vite-tsconfig-paths';
import { customOptimizeDeps } from './vite-plugin-customOptimizeDeps';
import { NodeModulesPolyfillPlugin } from '@esbuild-plugins/node-modules-polyfill';
import svgr from 'vite-plugin-svgr';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    reactRefresh(),
    tsconfigPaths(),
    svgr(),
    customOptimizeDeps({
      nodeModulesRoot: './',
      includedDeps: [],
      plugins: [NodeModulesPolyfillPlugin()],
    }),
  ],
  define: {
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
  },
  json: {
    stringify: true,
  },
  server: {
    open: true,
  },
  build: {
    outDir: 'build',
    assetsDir: 'dist',
    manifest: true,
  },
});

@nihalgonsalves
Copy link
Author

@carere You no longer need this gist, I added esbuild plugin support to Vite a couple of versions ago :) Looks like I still need to add the docs for it ... but you can supply optimizeDeps.esbuildOptions

@carere
Copy link

carere commented Jun 24, 2021

Yeah, i ased to the community on Discord, and they told me that this option is now available :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment