Compare commits

..

2 Commits

Author SHA1 Message Date
Sean Massa
4159b498b9 Publish Stable
- vercel@28.5.3
 - @vercel/static-build@1.0.38
2022-11-15 16:43:09 -06:00
Douglas Parsons
feabd64d5e [static-build] support gatsby-config as typescript (#8894)
### Related Issues

A customer issue was raised that web-vitals analytics were not working for their Gatsby application, even though this is meant to be zero config. 

It turns out the issue is due to their `gatsby-config` file being declared as a `ts` file, rather than `js`. This is perfectly valid and supported in Gatsby. 

However, the static-build modifications that are made to automatically add the `gatsby-plugin-vercel` only apply to existing `js` files. 

This lead to their deployments containing both a `js` and `ts` version of `gatsby-config`. Luckily, the `ts` version has higher precedence, so _only_ web-vitals were affected. 

Closes https://linear.app/vercel/issue/FLA-364/investigate-gatsby-and-nuxt-data-issues

#### Tests

- [X] The code changed/added as part of this PR has been covered with tests
- [X] All tests pass locally with `yarn test-unit`

#### Code Review

- [X] This PR has a concise title and thorough description useful to a reviewer
- [X] Issue from task tracker has a link to this PR
2022-11-15 22:37:18 +00:00
12 changed files with 9510 additions and 28 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "28.5.2",
"version": "28.5.3",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Vercel",
@@ -50,7 +50,7 @@
"@vercel/redwood": "1.0.36",
"@vercel/remix": "1.0.36",
"@vercel/ruby": "1.3.42",
"@vercel/static-build": "1.0.37",
"@vercel/static-build": "1.0.38",
"json5": "2.2.1",
"update-notifier": "5.1.0"
},

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/static-build",
"version": "1.0.37",
"version": "1.0.38",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/build-step",

View File

@@ -8,7 +8,7 @@ import {
writePackageJson,
} from './_shared';
const defaultConfig = {
const DEFAULT_CONFIG = {
plugins: [
{
resolve: 'gatsby-plugin-vercel',
@@ -16,42 +16,98 @@ const defaultConfig = {
},
],
};
const GATSBY_PLUGIN_PACKAGE_NAME = 'gatsby-plugin-vercel';
const GATSBY_CONFIG_FILE = 'gatsby-config';
export async function injectVercelAnalyticsPlugin(dir: string) {
export async function injectVercelAnalyticsPlugin(dir: string): Promise<void> {
// Gatsby requires a special variable name for environment variables to be
// exposed to the client-side JavaScript bundles:
process.env.GATSBY_VERCEL_ANALYTICS_ID = process.env.VERCEL_ANALYTICS_ID;
const gatsbyConfigName = 'gatsby-config.js';
const gatsbyPluginPackageName = 'gatsby-plugin-vercel';
const gatsbyConfigPathJs = path.join(dir, `${GATSBY_CONFIG_FILE}.js`);
const gatsbyConfigPathTs = path.join(dir, `${GATSBY_CONFIG_FILE}.ts`);
if (await fileExists(gatsbyConfigPathTs)) {
console.log(
`Injecting Gatsby.js analytics plugin "${GATSBY_PLUGIN_PACKAGE_NAME}" to \`${gatsbyConfigPathTs}\``
);
await addGatsbyPackage(dir);
return updateGatsbyTsConfig(gatsbyConfigPathTs);
}
const gatsbyConfigPath = path.join(dir, gatsbyConfigName);
console.log(
`Injecting Gatsby.js analytics plugin "${gatsbyPluginPackageName}" to \`${gatsbyConfigPath}\``
`Injecting Gatsby.js analytics plugin "${GATSBY_PLUGIN_PACKAGE_NAME}" to \`${gatsbyConfigPathJs}\``
);
await addGatsbyPackage(dir);
if (await fileExists(gatsbyConfigPathJs)) {
await updateGatsbyJsConfig(gatsbyConfigPathJs);
} else {
await fs.writeFile(
gatsbyConfigPathJs,
`module.exports = ${JSON.stringify(DEFAULT_CONFIG)}`
);
}
}
async function addGatsbyPackage(dir: string): Promise<void> {
const pkgJson = (await readPackageJson(dir)) as DeepWriteable<PackageJson>;
if (!pkgJson.dependencies) {
pkgJson.dependencies = {};
}
if (!pkgJson.dependencies[gatsbyPluginPackageName]) {
if (!pkgJson.dependencies[GATSBY_PLUGIN_PACKAGE_NAME]) {
console.log(
`Adding "${gatsbyPluginPackageName}" to \`package.json\` "dependencies"`
`Adding "${GATSBY_PLUGIN_PACKAGE_NAME}" to \`package.json\` "dependencies"`
);
pkgJson.dependencies[gatsbyPluginPackageName] = 'latest';
pkgJson.dependencies[GATSBY_PLUGIN_PACKAGE_NAME] = 'latest';
await writePackageJson(dir, pkgJson);
}
}
if (await fileExists(gatsbyConfigPath)) {
await fs.rename(
gatsbyConfigPath,
gatsbyConfigPath + '.__vercel_builder_backup__.js'
);
async function updateGatsbyTsConfig(configPath: string): Promise<void> {
await fs.rename(configPath, configPath + '.__vercel_builder_backup__.ts');
await fs.writeFile(
gatsbyConfigPath,
`const userConfig = require("./gatsby-config.js.__vercel_builder_backup__.js");
await fs.writeFile(
configPath,
`import userConfig from "./gatsby-config.ts.__vercel_builder_backup__.ts";
import type { PluginRef } from "gatsby";
// https://github.com/gatsbyjs/gatsby/blob/354003fb2908e02ff12109ca3a02978a5a6e608c/packages/gatsby/src/bootstrap/prefer-default.ts
const preferDefault = (m: any) => (m && m.default) || m;
const vercelConfig = Object.assign(
{},
// https://github.com/gatsbyjs/gatsby/blob/a6ecfb2b01d761e8a3612b8ea132c698659923d9/packages/gatsby/src/services/initialize.ts#L113-L117
preferDefault(userConfig)
);
if (!vercelConfig.plugins) {
vercelConfig.plugins = [];
}
const hasPlugin = vercelConfig.plugins.find(
(p: PluginRef) =>
p && (p === "gatsby-plugin-vercel" || p.resolve === "gatsby-plugin-vercel")
);
if (!hasPlugin) {
vercelConfig.plugins = vercelConfig.plugins.slice();
vercelConfig.plugins.push({
resolve: "gatsby-plugin-vercel",
options: {},
});
}
export default vercelConfig;
`
);
}
async function updateGatsbyJsConfig(configPath: string): Promise<void> {
await fs.rename(configPath, configPath + '.__vercel_builder_backup__.js');
await fs.writeFile(
configPath,
`const userConfig = require("./gatsby-config.js.__vercel_builder_backup__.js");
// https://github.com/gatsbyjs/gatsby/blob/354003fb2908e02ff12109ca3a02978a5a6e608c/packages/gatsby/src/bootstrap/prefer-default.ts
const preferDefault = m => (m && m.default) || m;
@@ -80,11 +136,5 @@ if (!hasPlugin) {
module.exports = vercelConfig;
`
);
} else {
await fs.writeFile(
gatsbyConfigPath,
`module.exports = ${JSON.stringify(defaultConfig)}`
);
}
);
}

View File

@@ -3,7 +3,7 @@ import { update } from 'rc9';
import { PackageJson } from '@vercel/build-utils';
import { DeepWriteable, readPackageJson, writePackageJson } from './_shared';
// https://github.com/nuxt-community/web-vitals-module
// https://github.com/nuxt-modules/web-vitals
const ANALYTICS_PLUGIN_PACKAGE = '@nuxtjs/web-vitals';
export async function injectVercelAnalyticsPlugin(dir: string) {

View File

@@ -0,0 +1,7 @@
module.exports = {
siteMetadata: {
title: `Gatsby Typescript Config`,
siteUrl: `https://gatsby-typescript-config.vercel.app`,
},
plugins: [],
};

View File

@@ -0,0 +1,15 @@
{
"private": true,
"scripts": {
"develop": "gatsby develop",
"start": "gatsby develop",
"build": "gatsby build",
"serve": "gatsby serve",
"clean": "gatsby clean"
},
"dependencies": {
"gatsby": "^4.5.3",
"react": "^17.0.1",
"react-dom": "^17.0.1"
}
}

View File

@@ -0,0 +1,27 @@
import React from 'react';
import '../styles/index.css';
function Index() {
return (
<main>
<h1>Gatsby + API Route</h1>
<h2>
Deployed with{' '}
<a
href="https://vercel.com/docs"
target="_blank"
rel="noreferrer noopener"
>
Vercel
</a>
!
</h2>
<p>
This project is a <a href="https://www.gatsbyjs.org/">Gatsby</a> app
with typescript gatsby-config.ts.
</p>
</main>
);
}
export default Index;

View File

@@ -0,0 +1,44 @@
main {
align-content: center;
box-sizing: border-box;
display: grid;
font-family: 'SF Pro Text', 'SF Pro Icons', 'Helvetica Neue', 'Helvetica',
'Arial', sans-serif;
hyphens: auto;
line-height: 1.65;
margin: 0 auto;
max-width: 680px;
min-height: 100vh;
padding: 72px 0;
text-align: center;
}
h1 {
font-size: 45px;
}
h2 {
margin-top: 1.5em;
}
p {
font-size: 16px;
}
a {
border-bottom: 1px solid white;
color: #0076ff;
cursor: pointer;
text-decoration: none;
transition: all 0.2s ease;
}
a:hover {
border-bottom: 1px solid #0076ff;
}
code,
pre {
color: #d400ff;
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
Bitstream Vera Sans Mono, Courier New, monospace, serif;
font-size: 0.92em;
}
code:before,
code:after {
content: '\`';
}

View File

@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "esnext",
"lib": ["dom", "esnext"],
"jsx": "react",
"module": "esnext",
"moduleResolution": "node",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
},
"include": [
"./src/**/*",
"./gatsby-node.ts",
"./gatsby-config.ts",
"./plugins/**/*"
]
}

View File

@@ -0,0 +1,13 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/static-build",
"config": {
"zeroConfig": true,
"framework": "gatsby"
}
}
]
}

View File

@@ -257,6 +257,39 @@ it(
FOUR_MINUTES
);
it(
'Should build Gatsby with configuration defined in typescript',
async () => {
const { workPath } = await runBuildLambda(
path.join(__dirname, 'build-fixtures/13-gatsby-with-typescript-config')
);
const contents = await fs.readdir(workPath);
expect(contents.some(name => name === 'gatsby-config.js')).toBeFalsy();
expect(contents.some(name => name === 'gatsby-config.ts')).toBeTruthy();
expect(require(path.join(workPath, 'gatsby-config.ts')))
.toMatchInlineSnapshot(`
Object {
"default": Object {
"plugins": Array [
Object {
"options": Object {},
"resolve": "gatsby-plugin-vercel",
},
],
"siteMetadata": Object {
"siteUrl": "https://gatsby-typescript-config.vercel.app",
"title": "Gatsby Typescript Config",
},
},
}
`);
},
FOUR_MINUTES
);
it(
'Should build Nuxt.js with "@nuxtjs/web-vitals" plugin',
async () => {