Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detecting server imports on the client #2442

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts", "./src/ext-src/vite.config.ts"]
"include": ["vite.config.ts", "./src/ext-src/vite.config.ts", "./vite/detectServerImports.ts"]
}
6 changes: 5 additions & 1 deletion waspc/data/Generator/templates/react-app/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { mergeConfig } from "vite";
import react from "@vitejs/plugin-react";
import { defaultExclude } from "vitest/config"
import { detectServerImports } from "./vite/detectServerImports"

{=# customViteConfig.isDefined =}
// Ignoring the TS error because we are importing a file outside of TS root dir.
Expand All @@ -16,7 +17,10 @@ const _waspUserProvidedConfig = {};

const defaultViteConfig = {
base: "{= baseDir =}",
plugins: [react()],
plugins: [
react(),
detectServerImports(),
],
optimizeDeps: {
exclude: ['wasp']
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { type Plugin } from "vite";
import path from "path";

export function detectServerImports(): Plugin {
return {
name: 'wasp-detect-server-imports',
transform(code, filePath) {
const isInDotWaspFolder = filePath.includes("/.wasp/");

// We don't want to check for server imports in the Wasp
// framework code.
if (isInDotWaspFolder) {
return;
}

const imports = getImportsFromCode(code);

for (const imp of imports) {
if (imp.moduleName.startsWith("wasp/server")) {
throw new Error(getServerImportErrorMessage(imp, filePath));
}
}
},
};
}

type Import = {
importStatement: string;
moduleName: string;
}

const importStatementRegex = /\s*import\s+(?:(?:[\w*\s{},]*)\s+from\s+)?(['"`])([^'"`]+)\1\s*/g;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't dive deep, just wanted to check, since this is regex, is there a chance of false positives? If so, in which situations, and are we ok with that? If not, can we do it better?


function* getImportsFromCode(code: string): Generator<Import> {
const matches = code.matchAll(importStatementRegex);
for (const match of matches) {
yield {
importStatement: match[0].trim(),
moduleName: match[2],
};
}
}

function getServerImportErrorMessage(imp: Import, filePath: string): string {
return `Client module "${getRelativeFilePath(filePath)}" imports server code:

${imp.importStatement}

This is not supported in the client code.`;
}

const waspProjectDirAbsPath = getWaspProjectDirAbsPathFromCwd();

function getRelativeFilePath(filePath: string): string {
return filePath.replace(waspProjectDirAbsPath, "");
}

// We are not passing the waspProjectDir path from Haskell because
// our e2e tests stop working. Becuase we need to absolute path of the
// Wasp project directory, it contains things like the username of the
// user running the tests, which is different on different machines.
function getWaspProjectDirAbsPathFromCwd(): string {
const webAppDirAbsPath = process.cwd();
const waspProjectDirAbsPath = path.join(webAppDirAbsPath, "../../../");
return waspProjectDirAbsPath;
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading