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

chore(gatsby) Rewrite requires-writer.js to TypeScript #24289

Merged
merged 1 commit into from
May 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/gatsby/src/bootstrap/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ process.on(`unhandledRejection`, (reason, p) => {

import { createGraphQLRunner } from "./create-graphql-runner"
const { extractQueries } = require(`../query/query-watcher`)
const requiresWriter = require(`./requires-writer`)
import * as requiresWriter from "./requires-writer"
import { writeRedirects, startRedirectListener } from "./redirects-writer"

// Override console.log to add the source file + line number.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
const _ = require(`lodash`)
const path = require(`path`)
const fs = require(`fs-extra`)
const crypto = require(`crypto`)
const { slash } = require(`gatsby-core-utils`)
const { store, emitter } = require(`../redux/`)
const reporter = require(`gatsby-cli/lib/reporter`)
const { match } = require(`@reach/router/lib/utils`)
import _ from "lodash"
import path from "path"
import fs from "fs-extra"
import crypto from "crypto"
import { slash } from "gatsby-core-utils"
import reporter from "gatsby-cli/lib/reporter"
import { match } from "@reach/router/lib/utils"
import { joinPath } from "gatsby-core-utils"
import { store, emitter } from "../redux/"
import { IGatsbyState, IGatsbyPage } from "../redux/types"

interface IGatsbyPageComponent {
component: string
componentChunkName: string
}

interface IGatsbyPageMatchPath {
path: string
matchPath: string | undefined
}

// path ranking algorithm copied (with small adjustments) from `@reach/router` (internal util, not exported from the package)
// https://github.com/reach/router/blob/28a79e7fc3a3487cb3304210dc3501efb8a50eba/src/lib/utils.js#L216-L254
Expand All @@ -18,11 +29,17 @@ const DYNAMIC_POINTS = 2
const SPLAT_PENALTY = 1
const ROOT_POINTS = 1

const isRootSegment = segment => segment === ``
const isDynamic = segment => paramRe.test(segment)
const isSplat = segment => segment === `*`
const isRootSegment = (segment: string): boolean => segment === ``
const isDynamic = (segment: string): boolean => paramRe.test(segment)
const isSplat = (segment: string): boolean => segment === `*`

const segmentize = (uri: string): string[] =>
uri
// strip starting/ending slashes
.replace(/(^\/+|\/+$)/g, ``)
.split(`/`)

const rankRoute = path =>
const rankRoute = (path: string): number =>
segmentize(path).reduce((score, segment) => {
score += SEGMENT_POINTS
if (isRootSegment(segment)) score += ROOT_POINTS
Expand All @@ -31,24 +48,18 @@ const rankRoute = path =>
else score += STATIC_POINTS
return score
}, 0)

const segmentize = uri =>
uri
// strip starting/ending slashes
.replace(/(^\/+|\/+$)/g, ``)
.split(`/`)
// end of copied `@reach/router` internals

let lastHash = null
let lastHash: string | null = null

const resetLastHash = () => {
export const resetLastHash = (): void => {
lastHash = null
}

const pickComponentFields = page =>
const pickComponentFields = (page: IGatsbyPage): IGatsbyPageComponent =>
_.pick(page, [`component`, `componentChunkName`])

const getComponents = pages =>
export const getComponents = (pages: IGatsbyPage[]): IGatsbyPageComponent[] =>
_(pages)
.map(pickComponentFields)
.uniqBy(c => c.componentChunkName)
Expand All @@ -59,17 +70,36 @@ const getComponents = pages =>
* Get all dynamic routes and sort them by most specific at the top
* code is based on @reach/router match utility (https://github.com/reach/router/blob/152aff2352bc62cefc932e1b536de9efde6b64a5/src/lib/utils.js#L224-L254)
*/
const getMatchPaths = pages => {
const createMatchPathEntry = (page, index) => {
const getMatchPaths = (pages: IGatsbyPage[]): IGatsbyPageMatchPath[] => {
interface IMatchPathEntry extends IGatsbyPage {
index: number
score: number
matchPath: string
}

const createMatchPathEntry = (
page: IGatsbyPage,
index: number
): IMatchPathEntry => {
const { matchPath } = page

if (matchPath === undefined) {
return reporter.panic(
`Error: matchPath property is undefined for page ${page.path}, should be a string`
) as never
}

return {
...page,
matchPath,
index,
score: rankRoute(page.matchPath),
score: rankRoute(matchPath),
}
}

const matchPathPages = []
pages.forEach((page, index) => {
const matchPathPages: IMatchPathEntry[] = []

pages.forEach((page: IGatsbyPage, index: number): void => {
if (page.matchPath) {
matchPathPages.push(createMatchPathEntry(page, index))
}
Expand All @@ -81,8 +111,9 @@ const getMatchPaths = pages => {
// More info in https://github.com/gatsbyjs/gatsby/issues/16097
// small speedup: don't bother traversing when no matchPaths found.
if (matchPathPages.length) {
const newMatches = []
pages.forEach((page, index) => {
const newMatches: IMatchPathEntry[] = []

pages.forEach((page: IGatsbyPage, index: number): void => {
const isInsideMatchPath = !!matchPathPages.find(
pageWithMatchPath =>
!page.matchPath && match(pageWithMatchPath.matchPath, page.path)
Expand Down Expand Up @@ -121,14 +152,17 @@ const getMatchPaths = pages => {
})
}

const createHash = (matchPaths, components) =>
const createHash = (
matchPaths: IGatsbyPageMatchPath[],
components: IGatsbyPageComponent[]
): string =>
crypto
.createHash(`md5`)
.update(JSON.stringify({ matchPaths, components }))
.digest(`hex`)

// Write out pages information.
const writeAll = async state => {
export const writeAll = async (state: IGatsbyState): Promise<boolean> => {
// console.log(`on requiresWriter progress`)
const { program } = state
const pages = [...state.pages.values()]
Expand Down Expand Up @@ -161,7 +195,7 @@ const preferDefault = m => m && m.default || m
\n\n`
syncRequires += `exports.components = {\n${components
.map(
c =>
(c: IGatsbyPageComponent): string =>
` "${
c.componentChunkName
}": ${hotMethod}(preferDefault(require("${joinPath(c.component)}")))`
Expand All @@ -174,7 +208,7 @@ const preferDefault = m => m && m.default || m
const preferDefault = m => m && m.default || m
\n`
asyncRequires += `exports.components = {\n${components
.map(c => {
.map((c: IGatsbyPageComponent): string => {
// we need a relative import path to keep contenthash the same if directory changes
const relativeComponentPath = path.relative(
path.join(program.directory, `.cache`),
Expand All @@ -188,7 +222,7 @@ const preferDefault = m => m && m.default || m
.join(`,\n`)}
}\n\n`

const writeAndMove = (file, data) => {
const writeAndMove = (file: string, data: string): Promise<void> => {
const destination = joinPath(program.directory, `.cache`, file)
const tmp = `${destination}.${Date.now()}`
return fs
Expand All @@ -206,7 +240,7 @@ const preferDefault = m => m && m.default || m
}

const debouncedWriteAll = _.debounce(
async () => {
async (): Promise<void> => {
const activity = reporter.activityTimer(`write out requires`, {
id: `requires-writer`,
})
Expand All @@ -229,31 +263,24 @@ const debouncedWriteAll = _.debounce(
* Start listening to CREATE/DELETE_PAGE events so we can rewrite
* files as required
*/
const startListener = () => {
emitter.on(`CREATE_PAGE`, () => {
export const startListener = (): void => {
emitter.on(`CREATE_PAGE`, (): void => {
reporter.pendingActivity({ id: `requires-writer` })
debouncedWriteAll()
})

emitter.on(`CREATE_PAGE_END`, () => {
emitter.on(`CREATE_PAGE_END`, (): void => {
reporter.pendingActivity({ id: `requires-writer` })
debouncedWriteAll()
})

emitter.on(`DELETE_PAGE`, () => {
emitter.on(`DELETE_PAGE`, (): void => {
reporter.pendingActivity({ id: `requires-writer` })
debouncedWriteAll()
})

emitter.on(`DELETE_PAGE_BY_PATH`, () => {
emitter.on(`DELETE_PAGE_BY_PATH`, (): void => {
reporter.pendingActivity({ id: `requires-writer` })
debouncedWriteAll()
})
}

module.exports = {
writeAll,
resetLastHash,
startListener,
getComponents,
}
2 changes: 1 addition & 1 deletion packages/gatsby/src/commands/develop-process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import { detectPortInUseAndPrompt } from "../utils/detect-port-in-use-and-prompt
import onExit from "signal-exit"
import queryUtil from "../query"
import queryWatcher from "../query/query-watcher"
import requiresWriter from "../bootstrap/requires-writer"
import * as requiresWriter from "../bootstrap/requires-writer"
import {
reportWebpackWarnings,
structureWebpackErrors,
Expand Down