-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
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
feat(schema,nuxt): add shared
folder to alias and auto-imports
#28682
Conversation
Run & review this pull request in StackBlitz Codeflow. |
shared
folder to alias and auto-imports
b9356a1
to
3114d48
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great!
The next step is to configure import protection so that we do not use certain protected imports in that folder...
What do you mean? I never heard this term before. Do you have an example? Edit Oh, you mean, protecting against unwanted imports like vue / nitro related stuff within the |
You can add patterns for the shared directory here: nuxt/packages/nuxt/src/core/plugins/import-protection.ts Lines 12 to 52 in 77e36ee
Or let me know, and I'll happily implement. 🙏 |
Thanks to @manniL I could push a new plugin with a different |
I'm facing another issue. Everything in the |
Is there anything in |
@Barbapapazes I think adding the import protection for folders is a good first step. (cc @danielroe if you have ideas how to protect from |
WalkthroughThe changes in this pull request involve significant updates to the Nitro framework configuration within a Nuxt application. Key modifications include the introduction of a new Changes
Assessment against linked issues
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (4)
packages/nuxt/test/import-protection.test.ts (1)
41-50
: Consider adding runtime validation for context parameterWhile the TypeScript type union ensures type safety at compile time, consider adding runtime validation for the context parameter to provide clearer error messages during testing.
Example implementation:
const transformWithImportProtection = (id: string, importer: string, context: 'nitro-app' | 'nuxt-app' | 'shared') => { + const validContexts = ['nitro-app', 'nuxt-app', 'shared'] as const + if (!validContexts.includes(context as any)) { + throw new Error(`Invalid context "${context}". Must be one of: ${validContexts.join(', ')}`) + } const plugin = ImpoundPlugin.rollup({ cwd: '/root', patterns: createImportProtectionPatterns({packages/vite/src/server.ts (1)
84-90
: LGTM: Robust external dependencies configuration.The external dependencies configuration correctly implements the
#shared
alias requirements:
- Explicitly marks
#shared
as external- Properly handles the shared directory path with safe RegExp escaping and correct path normalization
Consider adding a debug log to help troubleshoot the resolved shared directory path:
external: [ 'nitro/runtime', '#internal/nuxt/paths', '#internal/nuxt/app-config', '#shared', + // Log the resolved path in development + process.env.DEBUG && console.log('Shared dir pattern:', escapeStringRegexp(withTrailingSlash(resolve(ctx.nuxt.options.rootDir, ctx.nuxt.options.dir.shared)))), new RegExp('^' + escapeStringRegexp(withTrailingSlash(resolve(ctx.nuxt.options.rootDir, ctx.nuxt.options.dir.shared)))), ],packages/schema/src/config/common.ts (1)
358-361
: Enhance documentation for theshared
directory.The current documentation should be expanded to include important constraints and usage guidelines.
/** - * The shared directory. This directory is shared between the app and the server. + * The shared directory containing pure JavaScript/TypeScript code that can be imported by both + * the app and server directories. This directory must not contain Vue components or have + * dependencies on Vue or Nitro frameworks to maintain proper separation of concerns. */ shared: 'shared',packages/nuxt/src/core/plugins/import-protection.ts (1)
59-63
: Standardize context descriptions incontextFlags
In the
contextFlags
object, consider adjusting the description for the'shared'
context from'the #shared directory'
to'`#shared`'
. This change ensures that error messages read naturally and consistently across different contexts, for example: "nuxt
cannot be imported directly in#shared
."Proposed change:
const contextFlags = { 'nitro-app': 'server runtime', 'nuxt-app': 'the Vue part of your app', - 'shared': 'the #shared directory', + 'shared': '`#shared`', } as const
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (10)
packages/nuxt/src/core/nitro.ts
(4 hunks)packages/nuxt/src/core/nuxt.ts
(2 hunks)packages/nuxt/src/core/plugins/import-protection.ts
(2 hunks)packages/nuxt/src/imports/module.ts
(2 hunks)packages/nuxt/test/import-protection.test.ts
(3 hunks)packages/schema/src/config/common.ts
(2 hunks)packages/vite/src/server.ts
(2 hunks)packages/vite/src/utils/external.ts
(2 hunks)packages/vite/src/vite-node.ts
(1 hunks)packages/webpack/src/configs/server.ts
(2 hunks)
🔇 Additional comments (26)
packages/vite/src/utils/external.ts (6)
4-6
: LGTM: Imports support new shared directory path handling.
The new imports provide necessary utilities for safe path manipulation and type safety.
10-10
: LGTM: Improved function signature using object parameter pattern.
The change to accept a nuxt
object parameter improves maintainability by centralizing configuration access.
29-29
: LGTM: Consistent use of Nuxt configuration.
The update to use nuxt.options.modulesDir
aligns with the centralized configuration approach.
35-35
: LGTM: Consistent update to use Nuxt configuration.
The return statement correctly uses the rootDir from Nuxt options, maintaining consistency with the refactoring.
Line range hint 10-35
: Verify import protection mechanism.
The implementation adds the #shared
alias and path-based restrictions, but we should verify that it effectively prevents unwanted imports from Vue/Nitro in the shared folder as per PR objectives.
#!/bin/bash
# Description: Check for potential Vue/Nitro imports in shared folder
# Look for Vue imports in shared directory
rg "from ['|\"]vue['|\"]|from ['|\"]@vue" --type ts
# Look for Nitro imports in shared directory
rg "from ['|\"]nitro['|\"]|from ['|\"]@nitro" --type ts
# Look for import protection patterns in build configuration
rg -A 5 "noExternal|external.*shared" --type ts
23-24
: Verify Windows path compatibility.
The path handling looks correct, but we should verify that the regex pattern works correctly on Windows systems, particularly with path separators.
✅ Verification successful
Path handling is correctly implemented for Windows compatibility
The implementation is safe for Windows environments because:
- It uses Node's
resolve()
function which automatically handles path separators for the current OS - The regex pattern is created using
escapeStringRegexp()
which properly escapes all special characters - The
withTrailingSlash()
utility is used consistently across the codebase for both Windows and POSIX paths - Similar path handling patterns are used in other parts of the codebase (nitro, webpack) without platform-specific issues
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check if there are any Windows-specific path handling tests
# or related issues in the codebase
# Look for Windows path-related tests
rg -i "windows.*path|path.*windows" --type ts
# Look for path separator handling tests
rg -i "path\.sep|path\.delimiter" --type ts
# Look for related issues in test files
fd -e test.ts -e spec.ts -x rg -l "shared.*path|path.*shared" {}
Length of output: 13064
Script:
#!/bin/bash
# Let's check the implementation details around path handling
# Check the implementation of withTrailingSlash and related path utilities
ast-grep --pattern 'function withTrailingSlash'
# Look for path normalization or separator handling
rg -A 5 'normalize(Path|Separator)' --type ts
# Check if there are any Windows-specific path handling tests
fd -e test.ts -e spec.ts -x rg -l "\\\\|path\.sep" {}
# Check the actual implementation around shared directory resolution
rg -A 5 "dir\.shared" --type ts
Length of output: 4189
packages/nuxt/test/import-protection.test.ts (3)
4-4
: LGTM! Function rename improves clarity
The rename from nuxtImportProtections
to createImportProtectionPatterns
better describes the function's purpose.
31-31
: 🛠️ Refactor suggestion
Consider adding test cases for different contexts
The test currently only uses the 'nuxt-app' context. Given that the PR introduces import protection for different contexts ('nitro-app', 'nuxt-app', 'shared'), consider adding test cases that verify import protection behavior for each context.
Example test structure:
describe('import protection', () => {
describe.each(['nuxt-app', 'nitro-app', 'shared'] as const)('with %s context', (context) => {
it.each(testsToTriggerOn)('should protect %s', async (id, importer, isProtected) => {
const result = await transformWithImportProtection(id, importer, context)
// ... existing assertions
})
})
})
Line range hint 8-20
: Verify coverage of shared folder import constraints
The PR objectives specify that the shared
folder should not import from app
or server
. Let's verify if the test cases cover these scenarios.
Consider adding test cases like:
const sharedImportTests = [
['~/app/component', 'shared/utils/helper.ts', true], // should block
['~/server/api', 'shared/types/common.ts', true], // should block
['~/shared/utils', 'app/component.vue', false], // should allow
] as const
packages/webpack/src/configs/server.ts (2)
1-1
: LGTM: Import of resolve
from 'pathe'
The addition of resolve
from 'pathe' is appropriate for cross-platform path resolution, which is necessary for handling the shared directory path.
56-60
: Verify shared directory resolution and externalization
The changes correctly add support for the #shared
alias by:
- Adding the
#shared
alias to externals - Including the resolved shared directory path
However, we should verify that this implementation:
- Properly resolves the shared directory path across different Nuxt project structures
- Correctly handles the externalization of shared modules
Let's verify the implementation:
✅ Verification successful
Shared directory externalization implementation is correctly handled
The implementation is verified to be robust and consistent across the framework:
- The shared directory is properly configured in the schema and correctly resolved in Nuxt core using both absolute and relative paths
- The externalization is implemented consistently across both Webpack and Vite:
- Uses
#shared
alias - Includes the resolved absolute path
- Handles path normalization with trailing slashes
- Uses
- Additional protection is implemented via import protection plugins for both Vite and Webpack
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the shared directory resolution and usage
# Test 1: Check if the shared directory is consistently referenced across the codebase
echo "Checking shared directory references..."
rg -l "dir\.shared"
# Test 2: Verify the usage of #shared alias in imports
echo "Checking #shared alias usage..."
rg -l "#shared"
# Test 3: Look for potential circular dependencies
echo "Checking for potential circular dependencies..."
rg -l "from ['\"](#app|#server).*" ./shared
Length of output: 861
Script:
#!/bin/bash
# Let's analyze the implementation details of shared directory handling
# Check how shared directory is configured and used
echo "Checking shared directory configuration in schema..."
rg -A 5 "dir\.shared" packages/schema/src/config/common.ts
# Check how the shared directory is handled in Nuxt core
echo "Checking shared directory handling in Nuxt core..."
rg -A 10 "dir\.shared" packages/nuxt/src/core/nuxt.ts
# Check external handling in Vite config
echo "Checking Vite external handling..."
rg -A 5 "#shared" packages/vite/src/utils/external.ts
# Check if there are any imports using the #shared alias
echo "Checking actual #shared alias usage in imports..."
rg "from ['\"]#shared"
Length of output: 1941
packages/vite/src/vite-node.ts (1)
Line range hint 143-150
: Verify external module resolution with the new #shared
alias.
The change to pass the entire nuxt
context to createIsExternal
aligns with the PR objectives for implementing the #shared
alias. However, we should verify that external module resolution works correctly with the new shared folder structure.
Let's verify the external module resolution:
This change looks good, but consider adding tests to verify:
- The external module resolution with the
#shared
alias - The prevention of Vue/Nitro imports in the shared folder
✅ Verification successful
External module resolution change looks safe and well-implemented
The verification shows that the change to pass the entire nuxt
context to createIsExternal
is safe and consistent with the codebase:
- The
createIsExternal
implementation inpackages/vite/src/utils/external.ts
properly handles the Nuxt context - The
resolveModule
usage is consistent across the codebase and properly handles error cases - The change maintains compatibility with Vite's SSR external/noExternal configuration
The implementation correctly handles both the module resolution and error cases, making it suitable for the #shared
alias implementation.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for potential issues with external module resolution
# and shared folder imports.
# Test 1: Check if there are any direct imports from app/server to shared
echo "Checking for imports from app/server to shared..."
rg -g '!node_modules' -g 'app/**' -g 'server/**' "from ['\"].*shared.*['\"]"
# Test 2: Check if shared folder contains any Vue/Nitro imports
echo "Checking shared folder for Vue/Nitro imports..."
rg -g '!node_modules' -g 'shared/**' "from ['\"](@vue|@nuxt|vue|nuxt|nitro)['\"]"
# Test 3: Verify #shared alias usage
echo "Checking #shared alias usage..."
rg -g '!node_modules' "from ['\"]#shared.*['\"]"
Length of output: 810
Script:
#!/bin/bash
# Let's try a different approach to verify the external module resolution changes
# Check the implementation of createIsExternal function
echo "Checking createIsExternal implementation..."
rg -A 10 "function createIsExternal"
# Check for any existing tests related to external resolution
echo "Checking for related tests..."
fd -e test.ts -e spec.ts | xargs rg -l "external|isExternal"
# Look for other usages of resolveModule
echo "Checking resolveModule usage..."
rg "resolveModule\(" -A 2
# Check if there are any existing shared folder references
echo "Looking for shared folder patterns..."
fd shared
Length of output: 2196
packages/vite/src/server.ts (1)
10-10
: LGTM: Safe string escaping for RegExp.
The addition of escapeStringRegexp
is appropriate for safely handling path strings in RegExp patterns.
packages/nuxt/src/imports/module.ts (2)
57-58
: LGTM: Good use of feature flagging.
The isNuxtV4
flag is well-implemented to ensure backward compatibility while enabling new features for Nuxt v4.
70-73
: Consider adding import protection for shared directories.
While the directory structure is correctly implemented, consider adding import protection mechanisms to enforce the following requirements from the PR objectives:
- Prevent Vue/Nitro dependencies in the shared folder
- Prevent imports from
app
andserver
directories within the shared folder
Let's verify if import protection patterns exist:
Consider implementing import protection by:
- Adding patterns to prevent Vue/Nitro imports in shared files
- Adding patterns to prevent app/server imports in shared files
- Using static analysis tools to validate these constraints during build time
Would you like assistance in implementing these protection mechanisms?
packages/schema/src/config/common.ts (2)
432-432
: LGTM: Alias implementation is correct and consistent.
The #shared
alias is properly implemented:
- Resolves path relative to
rootDir
for compatibility with monorepo setups - Follows the same pattern as other directory aliases
Also applies to: 438-438
Line range hint 358-438
: Verify implementation of import protection for shared directory.
While the directory and alias setup looks good, we should verify that import protection is properly implemented to prevent importing from app
and server
directories within the shared
directory.
✅ Verification successful
Let's check the content of the file that matched our search to better understand the implementation.
Let's check the implementation of the import protection patterns and the ImpoundPlugin to ensure they properly prevent imports from app and server directories.
Let's check the specific implementation of the import protection patterns to verify the restrictions on app and server imports.
Import protection for shared directory is properly implemented
The implementation in import-protection.ts
confirms that the shared directory has proper import protection mechanisms:
- For shared directory context (
options.context === 'shared'
):- Prevents imports from Vue app aliases (
#app
,#build
) - Blocks imports from server directory (
server/(api|routes|middleware|plugins)
) - Uses ImpoundPlugin to enforce these restrictions at build time for both Vite and Webpack
- Prevents imports from Vue app aliases (
The implementation meets the PR objectives of preventing imports from app
and server
within the shared
directory.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for import protection implementation in the codebase
# Look for import protection patterns related to shared directory
echo "Searching for import protection implementation..."
rg -l "shared.*import.*protection" --type ts
# Look for specific import validation logic
echo "Searching for import validation logic..."
ast-grep --pattern 'function $name($$$) {
$$$
shared $$$
$$$
import $$$
$$$
}'
Length of output: 368
Script:
#!/bin/bash
# Check the content of the matched file
echo "Content of packages/nuxt/src/core/nuxt.ts:"
rg -A 10 -B 10 "shared.*import.*protection" packages/nuxt/src/core/nuxt.ts
# Look for any import validation or path checking logic
echo "\nSearching for import path validation patterns:"
ast-grep --pattern 'if ($condition) {
$$$
import $$$
$$$
}'
# Search for any build-time or runtime checks related to imports
echo "\nSearching for import-related hooks or plugins:"
rg -l "import.*check|validateImport|resolveImport" --type ts
Length of output: 1934
Script:
#!/bin/bash
# Check the implementation of import protection patterns
echo "Searching for createImportProtectionPatterns implementation:"
rg -A 10 "createImportProtectionPatterns" --type ts
# Look for ImpoundPlugin implementation
echo "\nSearching for ImpoundPlugin implementation:"
rg -A 10 "ImpoundPlugin" --type ts
# Check for any app/server import restrictions
echo "\nSearching for app/server import restrictions:"
rg -A 5 "app.*server.*import|import.*app.*server" --type ts
Length of output: 14526
Script:
#!/bin/bash
# Check the content of the import protection implementation
echo "Content of import protection patterns implementation:"
cat packages/nuxt/src/core/plugins/import-protection.ts
# Look for any tests verifying the import restrictions
echo "\nContent of import protection tests:"
cat packages/nuxt/test/import-protection.test.ts
Length of output: 4863
packages/nuxt/src/core/nitro.ts (5)
20-20
: Import 'createImportProtectionPatterns' added
The import statement for createImportProtectionPatterns
from './plugins/import-protection'
is correctly added and used appropriately in the code.
52-52
: Version compatibility check introduced
The introduction of isNuxtV4
provides a clear way to check for Nuxt version 4 compatibility using nuxt.options.future?.compatibilityVersion === 4
.
71-76
: Conditional inclusion of shared directories in imports
The imports.dirs
configuration now conditionally includes the shared utils
and types
directories when isNuxtV4
is true
, aligning with the PR objectives to facilitate auto-imports from the #shared
directory.
374-382
: Implementing import protection for 'shared' context
The code correctly adds an ImpoundPlugin
instance to enforce import protection patterns for the 'shared' context, using sharedPatterns
in the include
property and specifying the appropriate patterns.
383-386
: Extending import protection to 'nitro-app' context
The addition of import protection patterns for the 'nitro-app' context, with relevant exclude
patterns including sharedPatterns
, ensures that import rules are correctly enforced without interfering with the 'shared' context.
packages/nuxt/src/core/nuxt.ts (4)
34-34
: Import createImportProtectionPatterns
The import statement correctly brings in createImportProtectionPatterns
from ./plugins/import-protection
, aligning with its usage later in the code.
251-262
: Verify correctness of shared directory paths and import patterns
The code introduces import protection for the shared directory using sharedDir
, relativeSharedDir
, and sharedPatterns
. Please ensure that:
nuxt.options.dir.shared
is correctly defined and points to the intendedshared
directory.- Path resolutions with
resolve
andrelative
functions work correctly across different operating systems. - The regular expressions in
sharedPatterns
accurately match all intended import paths to and from theshared
directory.
260-261
: Confirm target environments for shared import protection plugins
The addVitePlugin
and addWebpackPlugin
functions are called with { server: false }
, applying the import protection only to the client-side build. If import protection is also required on the server-side, consider adjusting the options to ensure consistent protection across both client and server.
264-272
: Ensure exclusion of shared patterns from Nuxt import protection is intentional
In the nuxtProtectionConfig
, the exclude
array includes ...sharedPatterns
, which excludes the shared directory from this import protection configuration. Verify that this exclusion is intentional and aligns with the desired import protection behavior, especially considering the newly added shared directory import protection.
Why not share the Something like
Advantages
|
Hi there, |
It seems like this breaks the Nuxt build when using the Sentry Nuxt SDK where Sentry is adding a Rollup plugin that wraps the server entry with a dynamic This issue was filed by a user: getsentry/sentry-javascript#14179
What the Sentry Nuxt Rollup plugin does is similar to the polyfill code example in the Rollup docs: https://rollupjs.org/plugin-development/#resolveid This is the Rollup plugin in the Sentry Nuxt SDK: https://github.com/getsentry/sentry-javascript/blob/develop/packages/nuxt/src/vite/addServerConfig.ts#L116 Tell me if you need a reproduction :) |
Just tried the new shared folder, but found that auto import breaks for subfolders inside the ./shared/utils folder. I tried to specify a config folder in ./shared/utils/config/myConfig.ts and have mutiple files there but these are not auto imported |
@ThimoDEV The auto-imports is only top level. For files nested more deeply, you can import from |
@danielroe Makes sense that its not possible like with the components. If we would like to configure more folders for auto import besides the types and utils folder, we would need to add that in nuxt config imports setting, right? |
Correct 👍 |
Is there a reason why only the top level files in the |
Because it is the same behavior for composables, utils, modules, plugins |
Is this recommended practice if i need to auto import all nested folders of the /shared directory? (it seems to work)
|
you can just do |
Hi everyone! It seems no documentation has been added along with this PR, |
Also it seems that this feature requires Nuxt V4 although the blog post pretends it is also available for V3. Maybe either the PR or the blog post should be updated accordingly? |
Just noticed a bug (after enabling V4 😋): type aliases are not created if the filenames are |
@BlueskyFR Please raise an extra issue if you encounter problems 👍 |
🔗 Linked issue
fix #28675
📚 Description
Hello 👋,
This PR adds:
#shared
alias to bothtsconfig.json
andtsconfig.server.json
#shared/types
and#shared/utils
inapp
andserver
directoriesThe second bullet point is still in progress because I'm still trying to understand the usage of unimport within the project.So, after talking with @danielroe, this
#shared
folder is more complicated than expected. Here a list of expected behavior (that needs to be implemented)./app
folder can import (and auto-import) from the./shared
folder./server
folder can import (and auto-import) from the./shared
folder./shared
folder, you should not be able to import stuff from both./app
and./server
(could be achieved by excluding the file from thetsconfig.json
and a single chunk could be created)./shared
folder, you could (we need to decide if we want or not this behavior) import and auto-import stuff from the./shared
folder.At the end, the shared folder is just for pure JS (or TS) stuff. Nothing have to be related to Vue or Nitro.
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Documentation
Refactor