diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 68d3ffb9d6..411c41292b 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM node:lts +FROM node:lts@sha256:48db4f6ea21d134be744207225753a1730c4bc1b4cdf836d44511c36bf0e34d7 RUN apt-get update && \ apt-get install -fy libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdbus-1-3 libdrm2 libxkbcommon0 libatspi2.0-0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libasound2 && \ diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 0000000000..1ab482ad65 --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,10 @@ +paths: + - 'packages/*/dist/**' + - 'packages/nuxt/bin/**' + - 'packages/schema/schema/**' +paths-ignore: + - 'test/**' + - '**/*.test.js' + - '**/*.test.ts' + - '**/*.test.tsx' + - '**/__tests__/**' diff --git a/.github/workflows/cache-cleanup.yml b/.github/workflows/cache-cleanup.yml index b71b0e9baa..bda394c562 100644 --- a/.github/workflows/cache-cleanup.yml +++ b/.github/workflows/cache-cleanup.yml @@ -6,6 +6,8 @@ on: types: - closed +permissions: {} + jobs: cleanup: runs-on: ubuntu-latest @@ -20,14 +22,14 @@ jobs: gh extension install actions/gh-actions-cache echo "Fetching list of cache keys" - cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 ) + cacheKeysForPR=$(gh actions-cache list -R "$REPO" -B "$BRANCH" -L 100 | cut -f 1 ) ## Setting this to not fail the workflow while deleting cache keys. set +e echo "Deleting caches..." for cacheKey in $cacheKeysForPR do - gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm + gh actions-cache delete "$cacheKey" -R "$REPO" -B "$BRANCH" --confirm done echo "Done" env: diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 78474f90e2..5a3063f197 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -6,9 +6,7 @@ on: - main - 3.x -permissions: - pull-requests: write - contents: write +permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.event.number || github.sha }} @@ -19,6 +17,10 @@ jobs: if: github.repository_owner == 'nuxt' && !contains(github.event.head_commit.message, 'v3.') && !contains(github.event.head_commit.message, 'v4.') runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: write + steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0a1a219fcb..3e3ed0e17d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,8 +70,6 @@ jobs: actions: read contents: read security-events: write - needs: - - build steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 @@ -81,25 +79,26 @@ jobs: node-version: 20 cache: "pnpm" - - name: Install dependencies - run: pnpm install - - name: Initialize CodeQL uses: github/codeql-action/init@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3.26.6 with: - languages: javascript + config: | + paths: + - 'packages/*/src/**' + - 'packages/nuxt/bin/**' + - 'packages/schema/schema/**' + paths-ignore: + - 'test/**' + - '**/*.spec.ts' + - '**/*.test.ts' + - '**/__snapshots__/**' + languages: javascript-typescript queries: +security-and-quality - - name: Restore dist cache - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 - with: - name: dist - path: packages - - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3.26.6 with: - category: "/language:javascript" + category: "/language:javascript-typescript" typecheck: runs-on: ${{ matrix.os }} diff --git a/.github/workflows/label-issue.yml b/.github/workflows/label-issue.yml index e5ffb2b1d9..ebc2e3921b 100644 --- a/.github/workflows/label-issue.yml +++ b/.github/workflows/label-issue.yml @@ -5,21 +5,22 @@ on: types: - opened +permissions: + issues: write + jobs: - add-pr-labels: + add-issue-labels: name: Add labels runs-on: ubuntu-latest - permissions: - pull-requests: write if: github.repository == 'nuxt/nuxt' steps: - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: script: | - # add 'pending triage' label if issue is created with no labels + // add 'pending triage' label if issue is created with no labels if (context.payload.issue.labels.length === 0) { github.rest.issues.addLabels({ - issue_number: pullRequest.number, + issue_number: context.payload.issue.number, owner: context.repo.owner, repo: context.repo.repo, labels: ['pending triage'] diff --git a/.github/workflows/label-pr.yml b/.github/workflows/label-pr.yml index 82ec01db92..e0469e757f 100644 --- a/.github/workflows/label-pr.yml +++ b/.github/workflows/label-pr.yml @@ -8,6 +8,8 @@ on: - main - 3.x +permissions: {} + jobs: add-pr-labels: name: Add PR labels diff --git a/.github/workflows/lint-workflows.yml b/.github/workflows/lint-workflows.yml index 0820e5407f..219ef19670 100644 --- a/.github/workflows/lint-workflows.yml +++ b/.github/workflows/lint-workflows.yml @@ -26,6 +26,6 @@ jobs: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 # From https://github.com/rhysd/actionlint/blob/main/docs/usage.md#use-actionlint-on-github-actions - name: Check workflow files - run: | - bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/590d3bd9dde0c91f7a66071d40eb84716526e5a6/scripts/download-actionlint.bash) 1.6.25 - ./actionlint -color -shellcheck="" + uses: docker://rhysd/actionlint:1.7.1@sha256:435ecdb63b1169e80ca3e136290072548c07fc4d76a044cf5541021712f8f344 + with: + args: -color diff --git a/.github/workflows/notify-nuxt-bridge.yml b/.github/workflows/notify-nuxt-bridge.yml index fa97b12b95..b1f67c0509 100644 --- a/.github/workflows/notify-nuxt-bridge.yml +++ b/.github/workflows/notify-nuxt-bridge.yml @@ -4,6 +4,9 @@ on: types: [closed] paths: - "packages/nuxt/src/app/composables/**" + +permissions: {} + jobs: notify: if: github.event.pull_request.merged == true diff --git a/.github/workflows/release-pr.yml b/.github/workflows/release-pr.yml index 7850e0f264..9f38c8c9dc 100644 --- a/.github/workflows/release-pr.yml +++ b/.github/workflows/release-pr.yml @@ -39,7 +39,7 @@ jobs: GH_REPO: ${{ github.repository }} COMMENT_AT: ${{ github.event.comment.created_at }} run: | - pr="$(gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/${GH_REPO}/pulls/${PR_NUMBER})" + pr="$(gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/"${GH_REPO}"/pulls/"${PR_NUMBER}")" head_sha="$(echo "$pr" | jq -r .head.sha)" updated_at="$(echo "$pr" | jq -r .updated_at)" @@ -47,7 +47,7 @@ jobs: exit 1 fi - echo "head_sha=$head_sha" >> $GITHUB_OUTPUT + echo "head_sha=$head_sha" >> "$GITHUB_OUTPUT" - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: ref: ${{ steps.pr.outputs.head_sha }} diff --git a/.github/workflows/semantic-pull-requests.yml b/.github/workflows/semantic-pull-requests.yml index a3098e6f9e..e569c4acc3 100644 --- a/.github/workflows/semantic-pull-requests.yml +++ b/.github/workflows/semantic-pull-requests.yml @@ -7,12 +7,12 @@ on: - edited - synchronize -permissions: - contents: read +permissions: {} jobs: semantic-pr: permissions: + contents: read pull-requests: read # for amannn/action-semantic-pull-request to analyze PRs statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR if: github.repository == 'nuxt/nuxt' && !startsWith(github.head_ref, 'v') diff --git a/.github/workflows/stackblitz-link.yml b/.github/workflows/stackblitz-link.yml index 8403706f2e..997a48e846 100644 --- a/.github/workflows/stackblitz-link.yml +++ b/.github/workflows/stackblitz-link.yml @@ -11,7 +11,7 @@ jobs: stackblitz: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: huang-julien/reproduire-sur-stackblitz@v1.0.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: huang-julien/reproduire-sur-stackblitz@9ceccbfbb0f2f9a9a8db2d1f0dd909cf5cfe67aa # v1.0.2 with: reproduction-heading: '### Reproduction' diff --git a/package.json b/package.json index 5bccf459cd..44c054d0d2 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "nuxt": "workspace:*", "postcss": "8.4.45", "rollup": "4.21.2", + "send": ">=0.19.0", "typescript": "5.6.2", "ufo": "1.5.4", "vite": "5.4.4", diff --git a/packages/nuxt/src/app/components/dev-only.ts b/packages/nuxt/src/app/components/dev-only.ts index a1446dd3dd..94b5ae84e3 100644 --- a/packages/nuxt/src/app/components/dev-only.ts +++ b/packages/nuxt/src/app/components/dev-only.ts @@ -2,6 +2,7 @@ import { defineComponent } from 'vue' export default defineComponent({ name: 'DevOnly', + inheritAttrs: false, setup (_, props) { if (import.meta.dev) { return () => props.slots.default?.() diff --git a/packages/nuxt/src/app/components/island-renderer.ts b/packages/nuxt/src/app/components/island-renderer.ts index ebbca6fd43..189c980e50 100644 --- a/packages/nuxt/src/app/components/island-renderer.ts +++ b/packages/nuxt/src/app/components/island-renderer.ts @@ -8,6 +8,7 @@ import { createError } from '../composables/error' import { islandComponents } from '#build/components.islands.mjs' export default defineComponent({ + name: 'IslandRenderer', props: { context: { type: Object as () => { name: string, props?: Record }, diff --git a/packages/nuxt/src/app/components/nuxt-island.ts b/packages/nuxt/src/app/components/nuxt-island.ts index c9a4619c54..937f9d3136 100644 --- a/packages/nuxt/src/app/components/nuxt-island.ts +++ b/packages/nuxt/src/app/components/nuxt-island.ts @@ -45,6 +45,7 @@ async function loadComponents (source = appBaseURL, paths: NuxtIslandResponse['c export default defineComponent({ name: 'NuxtIsland', + inheritAttrs: false, props: { name: { type: String, diff --git a/packages/nuxt/src/app/components/nuxt-teleport-island-component.ts b/packages/nuxt/src/app/components/nuxt-teleport-island-component.ts index e459781dd2..875204ccf4 100644 --- a/packages/nuxt/src/app/components/nuxt-teleport-island-component.ts +++ b/packages/nuxt/src/app/components/nuxt-teleport-island-component.ts @@ -18,6 +18,7 @@ export const NuxtTeleportIslandSymbol = Symbol('NuxtTeleportIslandComponent') as /* @__PURE__ */ export default defineComponent({ name: 'NuxtTeleportIslandComponent', + inheritAttrs: false, props: { to: { type: String, diff --git a/packages/nuxt/src/app/components/nuxt-teleport-island-slot.ts b/packages/nuxt/src/app/components/nuxt-teleport-island-slot.ts index 9f9fefc8b1..7db8042735 100644 --- a/packages/nuxt/src/app/components/nuxt-teleport-island-slot.ts +++ b/packages/nuxt/src/app/components/nuxt-teleport-island-slot.ts @@ -9,6 +9,7 @@ import { NuxtTeleportIslandSymbol } from './nuxt-teleport-island-component' /* @__PURE__ */ export default defineComponent({ name: 'NuxtTeleportIslandSlot', + inheritAttrs: false, props: { name: { type: String, diff --git a/packages/nuxt/src/app/components/test-component-wrapper.ts b/packages/nuxt/src/app/components/test-component-wrapper.ts index 8b0da24381..b2de69d8f5 100644 --- a/packages/nuxt/src/app/components/test-component-wrapper.ts +++ b/packages/nuxt/src/app/components/test-component-wrapper.ts @@ -7,7 +7,7 @@ import { devRootDir } from '#build/nuxt.config.mjs' export default (url: string) => defineComponent({ name: 'NuxtTestComponentWrapper', - + inheritAttrs: false, async setup (props, { attrs }) { const query = parseQuery(new URL(url, 'http://localhost').search) const urlProps = query.props ? destr>(query.props as string) : {} diff --git a/packages/nuxt/src/app/nuxt.ts b/packages/nuxt/src/app/nuxt.ts index 7f61a8b621..130eaa8ceb 100644 --- a/packages/nuxt/src/app/nuxt.ts +++ b/packages/nuxt/src/app/nuxt.ts @@ -20,7 +20,7 @@ import type { LoadingIndicator } from '../app/composables/loading-indicator' import type { RouteAnnouncer } from '../app/composables/route-announcer' // @ts-expect-error virtual file -import { appId, multiApp } from '#build/nuxt.config.mjs' +import { appId, chunkErrorEvent, multiApp } from '#build/nuxt.config.mjs' // TODO: temporary module for backwards compatibility import type { DefaultAsyncDataErrorValue, DefaultErrorValue } from '#app/defaults' @@ -375,12 +375,14 @@ export function createNuxtApp (options: CreateOptions) { defineGetter(nuxtApp.vueApp, '$nuxt', nuxtApp) defineGetter(nuxtApp.vueApp.config.globalProperties, '$nuxt', nuxtApp) - // Listen to chunk load errors if (import.meta.client) { - window.addEventListener('nuxt.preloadError', (event) => { - nuxtApp.callHook('app:chunkError', { error: (event as Event & { payload: Error }).payload }) - }) - + // Listen to chunk load errors + if (chunkErrorEvent) { + window.addEventListener(chunkErrorEvent, (event) => { + nuxtApp.callHook('app:chunkError', { error: (event as Event & { payload: Error }).payload }) + event.preventDefault() + }) + } window.useNuxtApp = window.useNuxtApp || useNuxtApp // Log errors captured when running plugins, in the `app:created` and `app:beforeMount` hooks diff --git a/packages/nuxt/src/app/plugins/chunk-reload.client.ts b/packages/nuxt/src/app/plugins/chunk-reload.client.ts index e8eb5e2e48..c43d433428 100644 --- a/packages/nuxt/src/app/plugins/chunk-reload.client.ts +++ b/packages/nuxt/src/app/plugins/chunk-reload.client.ts @@ -26,7 +26,7 @@ export default defineNuxtPlugin({ }) router.onError((error, to) => { - if (chunkErrors.has(error)) { + if (chunkErrors.has(error) || error.message.includes('Failed to fetch dynamically imported module')) { reloadAppAtPath(to) } }) diff --git a/packages/nuxt/src/components/islandsTransform.ts b/packages/nuxt/src/components/islandsTransform.ts index e10f1cd957..d583e3425d 100644 --- a/packages/nuxt/src/components/islandsTransform.ts +++ b/packages/nuxt/src/components/islandsTransform.ts @@ -24,7 +24,7 @@ interface ComponentChunkOptions { buildDir: string } -const SCRIPT_RE = /]*>/g +const SCRIPT_RE = /]*>/gi const HAS_SLOT_OR_CLIENT_RE = /]*>|nuxt-client/ const TEMPLATE_RE = /