11import assert from "node:assert" ;
22import * as fs from "node:fs" ;
33import * as fsp from "node:fs/promises" ;
4- import { builtinModules } from "node:module" ;
54import * as path from "node:path" ;
65import { createMiddleware } from "@hattip/adapter-node" ;
76import MagicString from "magic-string" ;
@@ -31,6 +30,9 @@ import {
3130 injectGlobalCode ,
3231 isNodeCompat ,
3332 nodeCompatExternals ,
33+ NODEJS_MODULES_RE ,
34+ nodejsBuiltins ,
35+ NodeJsCompatWarnings ,
3436 resolveNodeJSImport ,
3537} from "./node-js-compat" ;
3638import { resolvePluginConfig } from "./plugin-config" ;
@@ -43,7 +45,11 @@ import {
4345} from "./utils" ;
4446import { handleWebSocket } from "./websockets" ;
4547import { getWarningForWorkersConfigs } from "./workers-configs" ;
46- import type { PluginConfig , ResolvedPluginConfig } from "./plugin-config" ;
48+ import type {
49+ PluginConfig ,
50+ ResolvedPluginConfig ,
51+ WorkerConfig ,
52+ } from "./plugin-config" ;
4753import type { Unstable_RawConfig } from "wrangler" ;
4854
4955export type { PluginConfig } from "./plugin-config" ;
@@ -66,6 +72,8 @@ export function cloudflare(pluginConfig: PluginConfig = {}): vite.Plugin[] {
6672
6773 const additionalModulePaths = new Set < string > ( ) ;
6874
75+ const nodeJsCompatWarningsMap = new Map < WorkerConfig , NodeJsCompatWarnings > ( ) ;
76+
6977 // This is set when the client environment is built to determine if the entry Worker should include assets
7078 let hasClientBuild = false ;
7179
@@ -522,10 +530,7 @@ export function cloudflare(pluginConfig: PluginConfig = {}): vite.Plugin[] {
522530 // Obviously we don't want/need the optimizer to try to process modules that are built-in;
523531 // But also we want to avoid following the ones that are polyfilled since the dependency-optimizer import analyzer does not
524532 // resolve these imports using our `resolveId()` hook causing the optimization step to fail.
525- exclude : [
526- ...builtinModules ,
527- ...builtinModules . map ( ( m ) => `node:${ m } ` ) ,
528- ] ,
533+ exclude : [ ...nodejsBuiltins ] ,
529534 } ,
530535 } ;
531536 }
@@ -619,7 +624,7 @@ export function cloudflare(pluginConfig: PluginConfig = {}): vite.Plugin[] {
619624 }
620625
621626 const workerNames = workerConfigs . map ( ( worker ) => {
622- assert ( worker . name ) ;
627+ assert ( worker . name , "Expected the Worker to have a name" ) ;
623628 return worker . name ;
624629 } ) ;
625630
@@ -639,6 +644,115 @@ export function cloudflare(pluginConfig: PluginConfig = {}): vite.Plugin[] {
639644 } ) ;
640645 } ,
641646 } ,
647+ // Plugin to warn if Node.js APIs are being used without nodejs_compat turned on
648+ {
649+ name : "vite-plugin-cloudflare:nodejs-compat-warnings" ,
650+ apply ( _config , env ) {
651+ // Skip this whole plugin if we are in preview mode
652+ return ! env . isPreview ;
653+ } ,
654+ configEnvironment ( environmentName ) {
655+ const workerConfig = getWorkerConfig ( environmentName ) ;
656+ if ( workerConfig && ! isNodeCompat ( workerConfig ) ) {
657+ return {
658+ optimizeDeps : {
659+ esbuildOptions : {
660+ plugins : [
661+ {
662+ name : "vite-plugin-cloudflare:nodejs-compat-warnings-resolver" ,
663+ setup ( build ) {
664+ build . onResolve (
665+ { filter : NODEJS_MODULES_RE } ,
666+ ( { path, importer } ) => {
667+ // We have to delay getting this `nodeJsCompatWarnings` from the `nodeJsCompatWarningsMap` until we are in this function.
668+ // It has not been added to the map until the `configureServer()` hook is called, which is after the `configEnvironment()` hook.
669+ const nodeJsCompatWarnings =
670+ nodeJsCompatWarningsMap . get ( workerConfig ) ;
671+ assert (
672+ nodeJsCompatWarnings ,
673+ `expected nodeJsCompatWarnings to be defined for Worker "${ workerConfig . name } "`
674+ ) ;
675+ nodeJsCompatWarnings . registerImport ( path , importer ) ;
676+ // Mark this path as external to avoid messy unwanted resolve errors.
677+ // It will fail at runtime but we will log warnings to the user.
678+ return { path, external : true } ;
679+ }
680+ ) ;
681+ build . onEnd ( ( ) => {
682+ const nodeJsCompatWarnings =
683+ nodeJsCompatWarningsMap . get ( workerConfig ) ;
684+ if ( nodeJsCompatWarnings ) {
685+ nodeJsCompatWarnings . renderWarnings ( ) ;
686+ }
687+ } ) ;
688+ } ,
689+ } ,
690+ ] ,
691+ } ,
692+ } ,
693+ } ;
694+ }
695+ } ,
696+ configureServer ( viteDevServer ) {
697+ // Create a nodeJsCompatWarnings object for each Worker environment that has Node.js compat turned off.
698+ for ( const environment of Object . values ( viteDevServer . environments ) ) {
699+ const workerConfig = getWorkerConfig ( environment . name ) ;
700+ if ( workerConfig && ! isNodeCompat ( workerConfig ) ) {
701+ nodeJsCompatWarningsMap . set (
702+ workerConfig ,
703+ new NodeJsCompatWarnings ( environment )
704+ ) ;
705+ }
706+ }
707+ } ,
708+ buildStart ( ) {
709+ const workerConfig = getWorkerConfig ( this . environment . name ) ;
710+ if ( workerConfig && ! isNodeCompat ( workerConfig ) ) {
711+ nodeJsCompatWarningsMap . set (
712+ workerConfig ,
713+ new NodeJsCompatWarnings ( this . environment )
714+ ) ;
715+ }
716+ } ,
717+ buildEnd ( ) {
718+ const workerConfig = getWorkerConfig ( this . environment . name ) ;
719+ if ( workerConfig && ! isNodeCompat ( workerConfig ) ) {
720+ const nodeJsCompatWarnings =
721+ nodeJsCompatWarningsMap . get ( workerConfig ) ;
722+ assert (
723+ nodeJsCompatWarnings ,
724+ `expected nodeJsCompatWarnings to be defined for Worker "${ workerConfig . name } "`
725+ ) ;
726+ nodeJsCompatWarnings . renderWarnings ( ) ;
727+ }
728+ } ,
729+ // We must ensure that the `resolveId` hook runs before the built-in ones otherwise we
730+ // never see the Node.js built-in imports since they get handled by default Vite behavior.
731+ enforce : "pre" ,
732+ async resolveId ( source , importer ) {
733+ const workerConfig = getWorkerConfig ( this . environment . name ) ;
734+ if ( workerConfig && ! isNodeCompat ( workerConfig ) ) {
735+ const nodeJsCompatWarnings =
736+ nodeJsCompatWarningsMap . get ( workerConfig ) ;
737+ assert (
738+ nodeJsCompatWarnings ,
739+ `expected nodeJsCompatWarnings to be defined for Worker "${ workerConfig . name } "`
740+ ) ;
741+ if ( nodejsBuiltins . has ( source ) ) {
742+ nodeJsCompatWarnings . registerImport ( source , importer ) ;
743+ // We don't have a natural place to trigger the rendering of the warnings
744+ // So we trigger a rendering to happen soon after this round of processing.
745+ nodeJsCompatWarnings . renderWarningsOnIdle ( ) ;
746+ // Mark this path as external to avoid messy unwanted resolve errors.
747+ // It will fail at runtime but we will log warnings to the user.
748+ return {
749+ id : source ,
750+ external : true ,
751+ } ;
752+ }
753+ }
754+ } ,
755+ } ,
642756 ] ;
643757
644758 function getWorkerConfig ( environmentName : string ) {
0 commit comments