Skip to content

Commit

Permalink
final ts conversions in context and entries
Browse files Browse the repository at this point in the history
  • Loading branch information
DanDroryAu committed Dec 18, 2024
1 parent 8662ac9 commit 0d372fa
Show file tree
Hide file tree
Showing 26 changed files with 162 additions and 118 deletions.
4 changes: 2 additions & 2 deletions fixtures/translations/src/server.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { renderToString } from 'react-dom/server';
import { VocabProvider } from '@vocab/react';
import { renderToString } from 'react-dom/server';
import type { Server } from 'sku';

import App from './App';
import type { Server } from 'sku';

const initialResponseTemplate = ({ headTags }: any) => /* html */ `
<!DOCTYPE html>
Expand Down
1 change: 1 addition & 0 deletions packages/sku/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@
"@types/react": "^18.2.3",
"@types/react-dom": "^18.2.3",
"@types/semver": "^7.5.8",
"@types/serialize-javascript": "^5.0.4",
"@types/serve-handler": "^6.1.4",
"@types/webpack-bundle-analyzer": "^4.7.0",
"@types/webpack-node-externals": "^3.0.4",
Expand Down
2 changes: 2 additions & 0 deletions packages/sku/src/config/webpack/webpack.config.ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ const makeWebpackConfig = ({

const serverEntry = require.resolve('../../entry/server/index.js');

console.log('serverEntry', serverEntry);

const publicPath = isDevServer ? clientServer : paths.publicPath;

const webpackStatsFilename = 'webpackStats.json';
Expand Down
14 changes: 0 additions & 14 deletions packages/sku/src/context/configPath.js

This file was deleted.

7 changes: 7 additions & 0 deletions packages/sku/src/context/configPath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
let configPath: string | undefined;

export const getConfigPath = () => configPath;

export const setConfigPath = (path: string | undefined) => {
configPath = path;
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Validator from 'fastest-validator';

// @ts-expect-error
const validator = new Validator();

const languagesToCompile = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { posix as path } from 'node:path';
import chalk from 'chalk';
import { fdir as Fdir } from 'fdir';
import _debug from 'debug';
import { createRequire } from 'node:module';

import toPosixPath from '../lib/toPosixPath.js';

import { rootDir, isPnpm } from '../lib/packageManager.js';
import _debug from 'debug';

const debug = _debug('sku:compilePackages');

/** @type {string[]} */
let detectedCompilePackages = [];
const require = createRequire(import.meta.url);

let detectedCompilePackages: string[] = [];

// If there's no rootDir, we're either inside `sku init`, or we can't determine the user's
// package manager. In either case, we can't correctly detect compile packages.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import browserslistConfigSeek from 'browserslist-config-seek';
import { join } from 'node:path';
import isCompilePackage from '../lib/isCompilePackage.js';
import type { SkuConfig } from '../../sku-types.d.ts';

const defaultDecorator = (a) => a;
const defaultDecorator = (a: any) => a;

/** @type {import("../../sku-types.d.ts").SkuConfig} */
export default {
clientEntry: 'src/client.js',
renderEntry: 'src/render.js',
serverEntry: 'src/server.js',
libraryEntry: null,
libraryEntry: undefined,
routes: [],
sites: [],
environments: [],
Expand All @@ -21,13 +21,13 @@ export default {
port: 8080,
serverPort: 8181,
target: 'dist',
setupTests: null,
initialPath: null,
setupTests: undefined,
initialPath: undefined,
public: 'public',
publicPath: '/',
polyfills: [],
libraryName: null,
libraryFile: null,
libraryName: undefined,
libraryFile: undefined,
sourceMapsProd: true,
displayNamesProd: false,
dangerouslySetWebpackConfig: defaultDecorator,
Expand All @@ -39,9 +39,9 @@ export default {
cspEnabled: false,
cspExtraScriptSrcHosts: [],
httpsDevServer: false,
devServerMiddleware: null,
devServerMiddleware: undefined,
rootResolution: !isCompilePackage,
languages: null,
languages: undefined,
skipPackageCompatibilityCompilation: [],
externalizeNodeModules: false,
};
} satisfies SkuConfig;
14 changes: 0 additions & 14 deletions packages/sku/src/context/packageManager.js

This file was deleted.

7 changes: 7 additions & 0 deletions packages/sku/src/context/packageManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
let packageManager: string | undefined;

export const getPackageManager = () => packageManager;

export const setPackageManager = (pm: string | undefined) => {
packageManager = pm;
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@ import didYouMean from 'didyoumean2';
import configSchema from './configSchema.js';
import defaultSkuConfig from './defaultSkuConfig.js';
import defaultClientEntry from './defaultClientEntry.js';
import type { SkuConfig } from '../../sku-types.d.ts';
import { hasErrorMessage } from '../lib/utils/error-guards.js';

const availableConfigKeys = Object.keys(defaultSkuConfig);

const exitWithErrors = async (errors) => {
const exitWithErrors = async (errors: string[]) => {
console.log(chalk.bold(chalk.underline(chalk.red('Errors in sku config:'))));
errors.forEach((error) => {
console.log(chalk.yellow(error));
});
process.exit(1);
};

export default (skuConfig) => {
export default (skuConfig: SkuConfig) => {
const errors = [];

// Validate extra keys
Expand All @@ -34,13 +36,15 @@ export default (skuConfig) => {
// Validate schema types
const schemaCheckResult = configSchema(skuConfig);
if (schemaCheckResult !== true) {
schemaCheckResult.forEach(({ message, field }) => {
const errorMessage = message
? `🚫 ${message.replace(field, `${chalk.bold(field)}`)}`
: `🚫 '${chalk.bold(field)}' is invalid`;
schemaCheckResult.forEach(
({ message, field }: { message: string; field: string }) => {
const errorMessage = message
? `🚫 ${message.replace(field, `${chalk.bold(field)}`)}`
: `🚫 '${chalk.bold(field)}' is invalid`;

errors.push(errorMessage);
});
errors.push(errorMessage);
},
);
}

// Validate library entry has corresponding libraryName
Expand All @@ -55,25 +59,29 @@ export default (skuConfig) => {
}

// Ensure defaultClientEntry is not configured as a route name
skuConfig.routes.forEach(({ name }) => {
if (name === defaultClientEntry) {
errors.push(
`🚫 Invalid route name: '${chalk.bold(
defaultClientEntry,
)}', please use a different route name`,
);
skuConfig.routes?.forEach((skuRoute) => {
if (typeof skuRoute !== 'string') {
if (skuRoute.name === defaultClientEntry) {
errors.push(
`🚫 Invalid route name: '${chalk.bold(
defaultClientEntry,
)}', please use a different route name`,
);
}
}
});

// Ensure supportedBrowsers is valid browserslist query
try {
browserslist(skuConfig.supportedBrowsers);
} catch (e) {
errors.push(
`🚫 '${chalk.bold(
'supportedBrowsers',
)}' must be a valid browserslist query. ${chalk.white(e.message)}`,
);
if (hasErrorMessage(e)) {
errors.push(
`🚫 '${chalk.bold(
'supportedBrowsers',
)}' must be a valid browserslist query. ${chalk.white(e.message)}`,
);
}
}

if (errors.length > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
import client from '__sku_alias__clientEntry';

import { loadableReady } from '@loadable/component';
import { createRequire } from 'node:module';

import clientContextKey from '../clientContextKey.js';

const require = createRequire(import.meta.url);

if (process.env.NODE_ENV === 'development') {
if (typeof client !== 'function') {
throw new Error(require('dedent')`
Expand All @@ -31,7 +34,7 @@ loadableReady(() => {

const dataElement = document.getElementById(clientContextKey);
if (dataElement) {
clientContext = JSON.parse(dataElement.textContent);
clientContext = JSON.parse(dataElement.textContent || '{}');
}

client(clientContext);
Expand Down
File renamed without changes.
File renamed without changes.
45 changes: 15 additions & 30 deletions packages/sku/src/entry/csp.js → packages/sku/src/entry/csp.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,35 @@
// @ts-check
import { createHash } from 'node:crypto';
import { parse, valid } from 'node-html-parser';
import { createHash, type BinaryLike } from 'node:crypto';
import { parse, valid, type HTMLElement } from 'node-html-parser';
import { URL } from 'node:url';
import type { RenderCallbackParams } from '../../sku-types.d.ts';

const scriptTypeIgnoreList = ['application/json', 'application/ld+json'];

const defaultBaseName = 'http://relative-url';

/** @typedef {import("node:crypto").BinaryLike} BinaryLike */

/** @param {BinaryLike} scriptContents */
const hashScriptContents = (scriptContents) =>
const hashScriptContents = (scriptContents: BinaryLike) =>
createHash('sha256').update(scriptContents).digest('base64');

/**
* @typedef {object} CreateCSPHandlerOptions
* @property {string[]} [extraHosts=[]]
* @property {boolean} [isDevelopment=false]
* @param {CreateCSPHandlerOptions} [options={}]
*/
interface CreateCSPHandlerOptions {
extraHosts?: string[];
isDevelopment?: boolean;
}

export default function createCSPHandler({
extraHosts = [],
isDevelopment = false,
} = {}) {
}: CreateCSPHandlerOptions = {}) {
let tagReturned = false;
const hosts = new Set();
const shas = new Set();

/** @param {BinaryLike | undefined?} contents */
const addScriptContents = (contents) => {
const addScriptContents = (contents: BinaryLike | undefined) => {
if (contents) {
shas.add(hashScriptContents(contents));
}
};

/** @param {string} src */
const addScriptUrl = (src) => {
const addScriptUrl = (src: string) => {
const { origin } = new URL(src, defaultBaseName);

if (origin !== defaultBaseName) {
Expand All @@ -45,8 +39,7 @@ export default function createCSPHandler({

extraHosts.forEach((host) => addScriptUrl(host));

/** @param {import("node-html-parser").HTMLElement} scriptNode */
const processScriptNode = (scriptNode) => {
const processScriptNode = (scriptNode: HTMLElement) => {
const src = scriptNode.getAttribute('src');

if (src) {
Expand All @@ -60,8 +53,7 @@ export default function createCSPHandler({
}
};

/** @type {import("../../sku-types.d.ts").RenderCallbackParams['registerScript']} */
const registerScript = (script) => {
const registerScript: RenderCallbackParams['registerScript'] = (script) => {
if (tagReturned) {
throw new Error(
`Unable to register script. Content Security Policy already sent. Try registering scripts before calling flushHeadTags. Script: ${script.substr(
Expand All @@ -78,9 +70,6 @@ export default function createCSPHandler({
parse(script).querySelectorAll('script').forEach(processScriptNode);
};

/**
* @returns {string}
*/
const createCSPTag = () => {
tagReturned = true;

Expand All @@ -106,11 +95,7 @@ export default function createCSPHandler({
)};">`;
};

/**
* @param {string} html
* @returns {string}
*/
const handleHtml = (html) => {
const handleHtml = (html: string) => {
const root = parse(html, {
comment: true,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import render from '__sku_alias__renderEntry';
import type { RenderAppProps } from '../../../sku-types.d.ts';

const libraryName = __SKU_LIBRARY_NAME__;
const libraryFile = __SKU_LIBRARY_FILE__;
const publicPath = __SKU_PUBLIC_PATH__;

const libraryPath = `${publicPath}${libraryFile ?? libraryName}`;

export default (renderParams) => {
export default (renderParams: RenderAppProps) => {
const renderContext = { ...renderParams, libraryName, libraryFile };

return render.renderDocument({
Expand Down
Loading

0 comments on commit 0d372fa

Please sign in to comment.