summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Matthew Phillips <matthew@matthewphillips.info> 2021-06-23 16:01:32 -0400
committerGravatar GitHub <noreply@github.com> 2021-06-23 16:01:32 -0400
commite316c9578ce39e0c932ea01c3c500792b4b8a636 (patch)
tree524f44fa257f675af0cb7210a467dd4a11916868
parent3f3e4f12863910fc86cc1dfb0adb68635a8a512f (diff)
downloadastro-e316c9578ce39e0c932ea01c3c500792b4b8a636.tar.gz
astro-e316c9578ce39e0c932ea01c3c500792b4b8a636.tar.zst
astro-e316c9578ce39e0c932ea01c3c500792b4b8a636.zip
Allow usage of node builtins through node: prefix (#520)
* Start of allowing node builtins issue * Allow use of node:builtin * Produce an error in Astro files with bare builtin usage * Upgrade snowpack version bug fixes for packages that use `node:` * Document node builtins * Use the provided builtins list
-rw-r--r--docs/api.md19
-rw-r--r--package.json3
-rw-r--r--packages/astro/package.json2
-rw-r--r--packages/astro/src/compiler/codegen/index.ts4
-rw-r--r--packages/astro/src/external.ts9
-rw-r--r--packages/astro/src/node_builtins.ts5
-rw-r--r--packages/astro/src/runtime.ts4
-rw-r--r--packages/astro/test/builtins.test.js26
-rw-r--r--packages/astro/test/fixtures/builtins/package.json7
-rw-r--r--packages/astro/test/fixtures/builtins/packages/dep/main.js10
-rw-r--r--packages/astro/test/fixtures/builtins/packages/dep/package.json6
-rw-r--r--packages/astro/test/fixtures/builtins/snowpack.config.json3
-rw-r--r--packages/astro/test/fixtures/builtins/src/components/Version.astro9
-rw-r--r--packages/astro/test/fixtures/builtins/src/pages/bare.astro12
-rw-r--r--packages/astro/test/fixtures/builtins/src/pages/index.astro16
-rw-r--r--yarn.lock8
16 files changed, 136 insertions, 7 deletions
diff --git a/docs/api.md b/docs/api.md
index b511d473d..205d4d92a 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -174,3 +174,22 @@ export default function () {
[config]: ../README.md#%EF%B8%8F-configuration
[docs-collections]: ./collections.md
[rss]: #-rss-feed
+
+### Node builtins
+
+Astro aims to be compatible with multiple JavaScript runtimes in the future. This includes [Deno](https://deno.land/) and [Cloudflare Workers](https://workers.cloudflare.com/) which do not support Node builtin modules such as `fs`. We encourage Astro users to write their code as cross-environment as possible.
+
+Due to that, you cannot use Node modules that you're familiar with such as `fs` and `path`. Our aim is to provide alternative built in to Astro. If you're use case is not covered please let us know.
+
+However, if you *really* need to use these builtin modules we don't want to stop you. Node supports the `node:` prefix for importing builtins, and this is also supported by Astro. If you want to read a file, for example, you can do so like this:
+
+```jsx
+---
+import fs from 'node:fs/promises';
+
+const url = new URL('../../package.json', import.meta.url);
+const json = await fs.readFile(url, 'utf-8');
+const data = JSON.parse(json);
+---
+
+<span>Version: {data.version}</span> \ No newline at end of file
diff --git a/package.json b/package.json
index f836f2974..c19e80a6f 100644
--- a/package.json
+++ b/package.json
@@ -28,7 +28,8 @@
"tools/*",
"scripts",
"www",
- "docs-www"
+ "docs-www",
+ "packages/astro/test/fixtures/builtins/packages/*"
],
"volta": {
"node": "14.16.1",
diff --git a/packages/astro/package.json b/packages/astro/package.json
index df3f8541d..9d0ce7336 100644
--- a/packages/astro/package.json
+++ b/packages/astro/package.json
@@ -92,7 +92,7 @@
"sass": "^1.32.13",
"shorthash": "^0.0.2",
"slash": "^4.0.0",
- "snowpack": "^3.6.0",
+ "snowpack": "^3.6.1",
"source-map-support": "^0.5.19",
"string-width": "^5.0.0",
"tiny-glob": "^0.2.8",
diff --git a/packages/astro/src/compiler/codegen/index.ts b/packages/astro/src/compiler/codegen/index.ts
index 145c20576..96de21796 100644
--- a/packages/astro/src/compiler/codegen/index.ts
+++ b/packages/astro/src/compiler/codegen/index.ts
@@ -22,6 +22,7 @@ import { renderMarkdown } from '@astrojs/markdown-support';
import { transform } from '../transform/index.js';
import { PRISM_IMPORT } from '../transform/prism.js';
import { positionAt } from '../utils';
+import { nodeBuiltinsSet } from '../../node_builtins.js';
import { readFileSync } from 'fs';
const traverse: typeof babelTraverse.default = (babelTraverse.default as any).default;
@@ -327,6 +328,9 @@ function compileModule(module: Script, state: CodegenState, compileOptions: Comp
for (const componentImport of componentImports) {
const importUrl = componentImport.source.value;
+ if(nodeBuiltinsSet.has(importUrl)) {
+ throw new Error(`Node builtins must be prefixed with 'node:'. Use node:${importUrl} instead.`);
+ }
for (const specifier of componentImport.specifiers) {
const componentName = specifier.local.name;
state.components.set(componentName, {
diff --git a/packages/astro/src/external.ts b/packages/astro/src/external.ts
index c3f99281f..c48d6d4e1 100644
--- a/packages/astro/src/external.ts
+++ b/packages/astro/src/external.ts
@@ -1,4 +1,5 @@
import { createRequire } from 'module';
+import { nodeBuiltinsMap } from './node_builtins.js';
const require = createRequire(import.meta.url);
const pkg = require('../package.json');
@@ -17,7 +18,13 @@ const isAstroRenderer = (name: string) => {
// These packages should NOT be built by `esinstall`
// But might not be explicit dependencies of `astro`
-const denyList = ['prismjs/components/index.js', '@vue/server-renderer', '@astrojs/markdown-support'];
+const denyList = [
+ 'prismjs/components/index.js',
+ '@vue/server-renderer',
+ '@astrojs/markdown-support',
+ 'node:fs/promises',
+ ...nodeBuiltinsMap.values()
+];
export default Object.keys(pkg.dependencies)
// Filter out packages that should be loaded threw Snowpack
diff --git a/packages/astro/src/node_builtins.ts b/packages/astro/src/node_builtins.ts
new file mode 100644
index 000000000..dad2afd96
--- /dev/null
+++ b/packages/astro/src/node_builtins.ts
@@ -0,0 +1,5 @@
+
+import {builtinModules} from 'module';
+
+export const nodeBuiltinsSet = new Set(builtinModules);
+export const nodeBuiltinsMap = new Map(builtinModules.map(bareName => [bareName, 'node:' + bareName])); \ No newline at end of file
diff --git a/packages/astro/src/runtime.ts b/packages/astro/src/runtime.ts
index db3940b92..477da6df8 100644
--- a/packages/astro/src/runtime.ts
+++ b/packages/astro/src/runtime.ts
@@ -22,6 +22,7 @@ import { debug, info } from './logger.js';
import { configureSnowpackLogger } from './snowpack-logger.js';
import { searchForPage } from './search.js';
import snowpackExternals from './external.js';
+import { nodeBuiltinsMap } from './node_builtins.js';
import { ConfigManager } from './config_manager.js';
interface RuntimeConfig {
@@ -389,6 +390,9 @@ async function createSnowpack(astroConfig: AstroConfig, options: CreateSnowpackO
knownEntrypoints,
external: snowpackExternals,
},
+ alias: {
+ ...Object.fromEntries(nodeBuiltinsMap)
+ }
});
snowpack = await startSnowpackServer(
diff --git a/packages/astro/test/builtins.test.js b/packages/astro/test/builtins.test.js
new file mode 100644
index 000000000..23625e6f7
--- /dev/null
+++ b/packages/astro/test/builtins.test.js
@@ -0,0 +1,26 @@
+import { suite } from 'uvu';
+import * as assert from 'uvu/assert';
+import { doc } from './test-utils.js';
+import { setup } from './helpers.js';
+
+const Builtins = suite('Node builtins');
+
+setup(Builtins, './fixtures/builtins');
+
+Builtins('Can be used with the node: prefix', async ({ runtime }) => {
+ const result = await runtime.load('/');
+ if (result.error) throw new Error(result.error);
+
+ const $ = doc(result.contents);
+
+ assert.equal($('#version').text(), '1.2.0');
+ assert.equal($('#dep-version').text(), '0.0.1');
+});
+
+Builtins('Throw if using the non-prefixed version', async ({ runtime }) => {
+ const result = await runtime.load('/bare');
+ assert.ok(result.error, 'Produced an error');
+ assert.ok(/Use node:fs instead/.test(result.error.message));
+});
+
+Builtins.run();
diff --git a/packages/astro/test/fixtures/builtins/package.json b/packages/astro/test/fixtures/builtins/package.json
new file mode 100644
index 000000000..8923fbd49
--- /dev/null
+++ b/packages/astro/test/fixtures/builtins/package.json
@@ -0,0 +1,7 @@
+{
+ "name": "@astrojs/astro-test-builtins",
+ "version": "1.2.0",
+ "dependencies": {
+ "@astrojs/astro-test-builtins-dep": "file:./packages/dep"
+ }
+} \ No newline at end of file
diff --git a/packages/astro/test/fixtures/builtins/packages/dep/main.js b/packages/astro/test/fixtures/builtins/packages/dep/main.js
new file mode 100644
index 000000000..577976428
--- /dev/null
+++ b/packages/astro/test/fixtures/builtins/packages/dep/main.js
@@ -0,0 +1,10 @@
+import fs from 'fs';
+
+const readFile = fs.promises.readFile;
+
+export async function readJson(path) {
+ const json = await readFile(path, 'utf-8');
+ const data = JSON.parse(json);
+ return data;
+}
+
diff --git a/packages/astro/test/fixtures/builtins/packages/dep/package.json b/packages/astro/test/fixtures/builtins/packages/dep/package.json
new file mode 100644
index 000000000..808f1aa4a
--- /dev/null
+++ b/packages/astro/test/fixtures/builtins/packages/dep/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "@astrojs/astro-test-builtins-dep",
+ "version": "0.0.1",
+ "module": "main.js",
+ "main": "main.js"
+} \ No newline at end of file
diff --git a/packages/astro/test/fixtures/builtins/snowpack.config.json b/packages/astro/test/fixtures/builtins/snowpack.config.json
new file mode 100644
index 000000000..8f034781d
--- /dev/null
+++ b/packages/astro/test/fixtures/builtins/snowpack.config.json
@@ -0,0 +1,3 @@
+{
+ "workspaceRoot": "../../../../../"
+}
diff --git a/packages/astro/test/fixtures/builtins/src/components/Version.astro b/packages/astro/test/fixtures/builtins/src/components/Version.astro
new file mode 100644
index 000000000..2f37ba69f
--- /dev/null
+++ b/packages/astro/test/fixtures/builtins/src/components/Version.astro
@@ -0,0 +1,9 @@
+---
+import fs from 'node:fs/promises';
+
+const url = new URL('../../package.json', import.meta.url);
+const json = await fs.readFile(url, 'utf-8');
+const data = JSON.parse(json);
+---
+
+<span id="version">{data.version}</span> \ No newline at end of file
diff --git a/packages/astro/test/fixtures/builtins/src/pages/bare.astro b/packages/astro/test/fixtures/builtins/src/pages/bare.astro
new file mode 100644
index 000000000..32af9fd04
--- /dev/null
+++ b/packages/astro/test/fixtures/builtins/src/pages/bare.astro
@@ -0,0 +1,12 @@
+---
+import fs from 'fs';
+---
+
+<html>
+<head>
+<title>This should throw</title>
+</head>
+<body>
+<h1>Test</h1>
+</body>
+</html> \ No newline at end of file
diff --git a/packages/astro/test/fixtures/builtins/src/pages/index.astro b/packages/astro/test/fixtures/builtins/src/pages/index.astro
new file mode 100644
index 000000000..ef70a2b64
--- /dev/null
+++ b/packages/astro/test/fixtures/builtins/src/pages/index.astro
@@ -0,0 +1,16 @@
+---
+import Version from '../components/Version.astro';
+import { readJson } from '@astrojs/astro-test-builtins-dep';
+
+const depPath = new URL('../../packages/dep/package.json', import.meta.url);
+
+const title = 'My App';
+const depVersion = (await readJson(depPath)).version;
+---
+
+<title>{title}</title>
+
+<h1>{title}</h1>
+
+<Version />
+<span id="dep-version">{depVersion}</span> \ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 3a34c18e6..cccb5a6cc 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8940,10 +8940,10 @@ smartwrap@^1.2.3:
wcwidth "^1.0.1"
yargs "^15.1.0"
-snowpack@^3.6.0:
- version "3.6.0"
- resolved "https://registry.yarnpkg.com/snowpack/-/snowpack-3.6.0.tgz#4c1af4c760be88b1c65594f0fb90f57c99c2338d"
- integrity sha512-MCRkA3+vJTBxVtb2nwoHETMunzo96l10VsgUuxHXvxsFaZqAkdT50bViuEyFv6fhEujMh55oSHY9pCrxGYA0aQ==
+snowpack@^3.6.1:
+ version "3.6.1"
+ resolved "https://registry.yarnpkg.com/snowpack/-/snowpack-3.6.1.tgz#5ae64e012deebcafca00bede6a0bb5d81dc883a6"
+ integrity sha512-XS+zJIuWxAEYuni3iZqm7a0LDNhPMEfNvT0xf/aGGxWptILOzqYOGaj9nogrQc+una1vlraBwSgzB3zNwV2G5A==
dependencies:
cli-spinners "^2.5.0"
default-browser-id "^2.0.0"