Skip to content

Commit

Permalink
Support ECMAScript modules
Browse files Browse the repository at this point in the history
See [#320][0] and [#340][1].

[0]: #320
[1]: #340
  • Loading branch information
EvanHahn committed Dec 5, 2021
1 parent db9254c commit 483c25d
Show file tree
Hide file tree
Showing 49 changed files with 390 additions and 132 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/node_modules/

/dist/
/tmp-commonjs-index.ts

/coverage/
37 changes: 4 additions & 33 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# `package.json` is published to npm, so everything we add is included in the installed tarball.
# Removing the `files` key and replacing it with this `.npmignore` saves about 0.2 kB, which should improve installation performance slightly.
# Removing the `files` key and replacing it with this `.npmignore` saves some bytes, which should improve installation performance slightly.

*

Expand All @@ -8,36 +8,7 @@
!README.md
!SECURITY.md

!dist/index.js
!dist/index.cjs
!dist/index.d.ts

!dist/middlewares/content-security-policy/index.d.ts
!dist/middlewares/content-security-policy/index.js
!dist/middlewares/cross-origin-embedder-policy/index.d.ts
!dist/middlewares/cross-origin-embedder-policy/index.js
!dist/middlewares/cross-origin-opener-policy/index.d.ts
!dist/middlewares/cross-origin-opener-policy/index.js
!dist/middlewares/cross-origin-resource-policy/index.d.ts
!dist/middlewares/cross-origin-resource-policy/index.js
!dist/middlewares/expect-ct/index.d.ts
!dist/middlewares/expect-ct/index.js
!dist/middlewares/origin-agent-cluster/index.d.ts
!dist/middlewares/origin-agent-cluster/index.js
!dist/middlewares/referrer-policy/index.d.ts
!dist/middlewares/referrer-policy/index.js
!dist/middlewares/strict-transport-security/index.d.ts
!dist/middlewares/strict-transport-security/index.js
!dist/middlewares/x-content-type-options/index.d.ts
!dist/middlewares/x-content-type-options/index.js
!dist/middlewares/x-dns-prefetch-control/index.d.ts
!dist/middlewares/x-dns-prefetch-control/index.js
!dist/middlewares/x-download-options/index.d.ts
!dist/middlewares/x-download-options/index.js
!dist/middlewares/x-frame-options/index.d.ts
!dist/middlewares/x-frame-options/index.js
!dist/middlewares/x-permitted-cross-domain-policies/index.d.ts
!dist/middlewares/x-permitted-cross-domain-policies/index.js
!dist/middlewares/x-powered-by/index.d.ts
!dist/middlewares/x-powered-by/index.js
!dist/middlewares/x-xss-protection/index.d.ts
!dist/middlewares/x-xss-protection/index.js
!dist/index.js
!dist/middlewares/**/*.d.ts
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/dist/
/coverage/
17 changes: 5 additions & 12 deletions .prettierrc.js → .prettierrc-dist.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,9 @@ module.exports = {
// This shaves a few bytes off the built files while still keeping them readable.
// When testing on 4f550aab7ccf00a6dfe686d57195268b3ef06b1a, it reduces the tarball size by about 100 bytes.
// This should help installation performance slightly.
overrides: [
{
files: ["dist/**/*.js", "dist/**/*.d.ts"],
options: {
printWidth: 2000,
trailingComma: "none",
useTabs: true,
arrowParens: "avoid",
semi: false,
},
},
],
printWidth: 2000,
trailingComma: "none",
useTabs: true,
arrowParens: "avoid",
semi: false,
};
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

### 5.0.0 - ???

### Added

- ECMAScript module imports (i.e., `import helmet from "helmet"` and `import { frameguard } from "helmet"`). See [#320](https://github.com/helmetjs/helmet/issues/320)

### Changed

- **Breaking:** `helmet.contentSecurityPolicy`: `useDefaults` option now defaults to `true`
Expand Down
44 changes: 44 additions & 0 deletions MAINTAINER_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Helmet maintainer readme

These are notes for any maintainers of Helmet...which is currently just [Evan Hahn](https://evanhahn.com/). These notes may be of interest to future maintainers, contributors, or people making forks.

## Releasing Helmet

tl;dr:

- `npm publish` builds and releases the `helmet` package
- `npm run build-middleware-package -- $MIDDLEWARE_NAME` builds `$MIDDLEWARE_NAME` and puts it in a temporary directory to be published

Helmet releases have the following goals:

- Users should be able to import the package with CommonJS. The following code snippet should work as expected:

```js
const helmet = require("helmet");
app.use(helmet());
app.use(helmet.ieNoOpen());
```

- Users should be able to import the package with ECMAScript modules. The default export should be a function, and the rest of the functions should be available too. The following snippets should work as expected:

```js
import helmet from "helmet";
app.use(helmet());
```

```js
import { ieNoOpen } from "helmet";
app.use(ieNoOpen());
```

- TypeScript users should be able to import Helmet and various exported types.

```ts
import helmet, { HelmetOptions, ContentSecurityPolicyOptions } from "helmet";
```

- Some middlewares have their own npm packages, such as `helmet-csp` or `frameguard`.

- `helmet` should have no production dependencies, including middleware packages, to simplify installation.

To that end, there are special scripts for building `helmet` and for building middleware packages.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ app.use(helmet());
// ...
```

You can also use ECMAScript modules if you prefer.

```js
import helmet from "helmet";

const app = express();

app.use(helmet());
```

## How it works

Helmet is [Connect](https://github.com/senchalabs/connect)-style middleware, which is compatible with frameworks like [Express](https://expressjs.com/). (If you need support for other frameworks or languages, [see this list](https://helmetjs.github.io/see-also/).)
Expand Down
45 changes: 45 additions & 0 deletions bin/build-helmet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env node
import * as path from "path";
import { fileURLToPath } from "url";
import rollupTypescript from "@rollup/plugin-typescript";
import { writeRollup, withCommonJsFile } from "./helpers.js";

const thisPath = fileURLToPath(import.meta.url);
const rootPath = path.join(path.dirname(thisPath), "..");
const esmSourcePath = path.join(rootPath, "index.ts");
const esmDistPath = path.join(rootPath, "dist", "index.js");
const commonJsDistPath = path.join(rootPath, "dist", "index.cjs");

const compileEsm = () =>
writeRollup(
{
input: esmSourcePath,
plugins: [rollupTypescript({ tsconfig: "./tsconfig-esm.json" })],
},
{ file: esmDistPath }
);

const compileCommonjs = () =>
withCommonJsFile(esmSourcePath, (commonJsSourcePath) =>
writeRollup(
{
input: commonJsSourcePath,
plugins: [rollupTypescript({ tsconfig: "./tsconfig-commonjs.json" })],
},
{
exports: "default",
file: commonJsDistPath,
format: "cjs",
}
)
);

async function main() {
await compileEsm();
await compileCommonjs();
}

main(process.argv).catch((err) => {
console.error(err);
process.exit(1);
});
52 changes: 38 additions & 14 deletions bin/build-middleware-package.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
#!/usr/bin/env node
const path = require("path");
const fs = require("fs").promises;
const os = require("os");
const crypto = require("crypto");
import * as path from "path";
import { promises as fs } from "fs";
import * as os from "os";
import * as crypto from "crypto";
import { fileURLToPath } from "url";
import rollupTypescript from "@rollup/plugin-typescript";
import { writeRollup, withCommonJsFile } from "./helpers.js";

const PROJECT_ROOT_PATH = path.join(__dirname, "..");
const getRootFilePath = (filename) => path.join(PROJECT_ROOT_PATH, filename);
const thisPath = fileURLToPath(import.meta.url);
const rootPath = path.join(path.dirname(thisPath), "..");
const getRootFilePath = (filename) => path.join(rootPath, filename);

const readJson = async (path) => JSON.parse(await fs.readFile(path));

async function main(argv) {
if (argv.length !== 3) {
Expand All @@ -20,14 +26,12 @@ async function main(argv) {
);

const getSourceFilePath = (filename) =>
path.join(PROJECT_ROOT_PATH, "middlewares", argv[2], filename);
path.join(rootPath, "middlewares", argv[2], filename);
const getDistFilePath = (filename) =>
path.join(PROJECT_ROOT_PATH, "dist", "middlewares", argv[2], filename);
path.join(rootPath, "dist", "middlewares", argv[2], filename);
const getStagingFilePath = (filename) =>
path.join(stagingDirectoryPath, filename);

const packageFiles = require(getSourceFilePath("package-files.json"));

const packageJson = {
author: "Adam Baldwin <adam@npmjs.com> (https://evilpacket.net)",
contributors: ["Evan Hahn <me@evanhahn.com> (https://evanhahn.com)"],
Expand All @@ -44,14 +48,33 @@ async function main(argv) {
engines: {
node: ">=12.0.0",
},
files: ["CHANGELOG.md", "LICENSE", "README.md", ...packageFiles],
files: ["CHANGELOG.md", "LICENSE", "README.md", "index.js", "index.d.ts"],
main: "index.js",
typings: "index.d.ts",
...require(getSourceFilePath("package-overrides.json")),
exports: {
".": {
require: "./index.js",
types: "./index.d.ts",
},
},
...(await readJson(getSourceFilePath("package-overrides.json"))),
};

await fs.mkdir(stagingDirectoryPath, { recursive: true, mode: 0o700 });
await Promise.all([
withCommonJsFile(getSourceFilePath("index.ts"), (commonJsSourcePath) =>
writeRollup(
{
input: commonJsSourcePath,
plugins: [rollupTypescript()],
},
{
exports: "default",
file: getStagingFilePath("index.js"),
format: "cjs",
}
)
),
fs.writeFile(
getStagingFilePath("package.json"),
JSON.stringify(packageJson)
Expand All @@ -65,8 +88,9 @@ async function main(argv) {
getStagingFilePath("CHANGELOG.md")
),
fs.copyFile(getRootFilePath("LICENSE"), getStagingFilePath("LICENSE")),
...packageFiles.map((filename) =>
fs.copyFile(getDistFilePath(filename), getStagingFilePath(filename))
fs.copyFile(
getDistFilePath("index.d.ts"),
getStagingFilePath("index.d.ts")
),
]);

Expand Down
8 changes: 5 additions & 3 deletions bin/clean.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#!/usr/bin/env node
// This lets us remove files on all platforms. Notably, `rm` is missing on Windows.
const path = require("path");
const fs = require("fs");
import * as path from "path";
import * as fs from "fs";
import { fileURLToPath } from "url";

const distPath = path.join(__dirname, "..", "dist");
const thisPath = fileURLToPath(import.meta.url);
const distPath = path.join(path.dirname(thisPath), "..", "dist");

fs.rmSync(distPath, { recursive: true, force: true });
30 changes: 30 additions & 0 deletions bin/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as path from "path";
import { promises as fs } from "fs";
import { rollup } from "rollup";

export async function writeRollup(inputOptions, outputOptions) {
const bundle = await rollup(inputOptions);
await bundle.write(outputOptions);
await bundle.close();
}

export async function withCommonJsFile(esmSourcePath, fn) {
const commonJsSourcePath = path.join(
path.dirname(esmSourcePath),
"tmp-commonjs-index.ts"
);

const lines = (await fs.readFile(esmSourcePath, "utf8")).split(/\r?\n/);
const resultLines = lines.slice(
0,
lines.findIndex((line) => line.includes("!helmet-end-of-commonjs"))
);

try {
await fs.writeFile(commonJsSourcePath, resultLines.join("\n"));

await fn(commonJsSourcePath);
} finally {
await fs.unlink(commonJsSourcePath);
}
}
24 changes: 22 additions & 2 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import xPermittedCrossDomainPolicies, {
import xPoweredBy from "./middlewares/x-powered-by";
import xXssProtection from "./middlewares/x-xss-protection";

interface HelmetOptions {
export interface HelmetOptions {
contentSecurityPolicy?: ContentSecurityPolicyOptions | boolean;
crossOriginEmbedderPolicy?: boolean;
crossOriginOpenerPolicy?: CrossOriginOpenerPolicyOptions | boolean;
Expand Down Expand Up @@ -282,4 +282,24 @@ const helmet: Helmet = Object.assign(
}
);

export = helmet;
export default helmet;

// !helmet-end-of-commonjs

export {
contentSecurityPolicy,
crossOriginEmbedderPolicy,
crossOriginOpenerPolicy,
crossOriginResourcePolicy,
expectCt,
originAgentCluster,
referrerPolicy,
strictTransportSecurity as hsts,
xContentTypeOptions as noSniff,
xDnsPrefetchControl as dnsPrefetchControl,
xDownloadOptions as ieNoOpen,
xFrameOptions as frameguard,
xPermittedCrossDomainPolicies as permittedCrossDomainPolicies,
xPoweredBy as hidePoweredBy,
xXssProtection as xssFilter,
};
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {
export default {
collectCoverage: true,
collectCoverageFrom: ["/index.ts", "/middlewares/**/*.ts"],
coverageThreshold: {
Expand Down
4 changes: 3 additions & 1 deletion middlewares/content-security-policy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ contentSecurityPolicy.getDefaultDirectives = getDefaultDirectives;
contentSecurityPolicy.dangerouslyDisableDefaultSrc =
dangerouslyDisableDefaultSrc;

module.exports = contentSecurityPolicy;
export default contentSecurityPolicy;

// !helmet-end-of-commonjs

export { getDefaultDirectives, dangerouslyDisableDefaultSrc };
1 change: 0 additions & 1 deletion middlewares/content-security-policy/package-files.json

This file was deleted.

1 change: 0 additions & 1 deletion middlewares/cross-origin-embedder-policy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,4 @@ function crossOriginEmbedderPolicy() {
};
}

module.exports = crossOriginEmbedderPolicy;
export default crossOriginEmbedderPolicy;
1 change: 0 additions & 1 deletion middlewares/cross-origin-opener-policy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,4 @@ function crossOriginOpenerPolicy(
};
}

module.exports = crossOriginOpenerPolicy;
export default crossOriginOpenerPolicy;
Loading

0 comments on commit 483c25d

Please sign in to comment.