Skip to content

Add support during template creation for pnpm and bun (#2007) #2008

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
27 changes: 23 additions & 4 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ These are just first steps. You can continue to develop apps after publishing, a

## 1. Create

Framework includes a helper script (`observable create`) for creating new apps. After a few quick prompts — where to create the project, your preferred package manager, *etc.* — it will stamp out a fresh project from a template.
Framework includes a helper script (`observable create`) for creating new apps. After a few quick prompts — where to create the project, your preferred package manager, _etc._ — it will stamp out a fresh project from a template.

<div class="tip">
<p>Framework is a <a href="https://nodejs.org/">Node.js</a> application published to npm. You must have <a href="https://nodejs.org/en/download">Node.js 18 or later</a> installed before you can install Framework. Framework is a command-line interface (CLI) that runs in the terminal.</p>
Expand Down Expand Up @@ -146,6 +146,17 @@ Or with Yarn:

<pre data-copy>yarn dev</pre>

Or with Pnpm:

<pre data-copy>
pnpm approve-builds
pnpm dev
</pre>

Or with Bun:

<pre data-copy>bun dev</pre>

You should see something like this:

<pre data-copy="none"><b class="green">Observable Framework</b> v1.13.3
Expand Down Expand Up @@ -181,7 +192,7 @@ Now visit <http://127.0.0.1:3000> in your browser, which should look like:

### Test live preview

Live preview means that as you save changes, your in-browser preview updates instantly. Live preview applies to Markdown pages, imported JavaScript modules (so-called *hot module replacement*), data loaders, page loaders, and file attachments. This feature is implemented by the preview server watching files and pushing changes to the browser over a socket.
Live preview means that as you save changes, your in-browser preview updates instantly. Live preview applies to Markdown pages, imported JavaScript modules (so-called _hot module replacement_), data loaders, page loaders, and file attachments. This feature is implemented by the preview server watching files and pushing changes to the browser over a socket.

To experience live preview, open <code>src/index.md</code> in your preferred text editor — below we show Zed — and position your browser window so that you can see your editor and browser side-by-side. If you then replace the text “Hello Framework” with “Hi, Mom!” and save, you should see:

Expand Down Expand Up @@ -219,7 +230,7 @@ If you click on the **Weather report** link in the sidebar, it’ll take you to

<div class="tip">The sidebar is hidden by default in narrow windows. If you don’t see the sidebar, you can show it by making the window wider, or using Command-B (⌘B) or Option-B (⌥B) on Firefox and non-macOS, or clicking the right-pointing arrow ↦ on the left edge of the window.</div>

As evidenced by the code <code class="language-js">1 + 2</code> rendered as <code class="language-js">3</code>, JavaScript fenced code blocks (<code>```js</code>) are *live*: the code runs in the browser. Try replacing <code class="language-js">2</code> with <code class="language-js">Math.random()</code>, and the code will re-run automatically on save. In a bit, we’ll write code to render a chart. We can also use code to debug as we develop, say to inspect data.
As evidenced by the code <code class="language-js">1 + 2</code> rendered as <code class="language-js">3</code>, JavaScript fenced code blocks (<code>```js</code>) are _live_: the code runs in the browser. Try replacing <code class="language-js">2</code> with <code class="language-js">Math.random()</code>, and the code will re-run automatically on save. In a bit, we’ll write code to render a chart. We can also use code to debug as we develop, say to inspect data.

### Data loader

Expand Down Expand Up @@ -397,7 +408,7 @@ As before, the code block contains an expression (a call to `Plot.plot`) and hen

### Components

As pages grow, complex inline JavaScript may become unwieldy and repetitive. Tidy code by moving it into functions. In Framework, a function that returns a DOM element is called a *component*.
As pages grow, complex inline JavaScript may become unwieldy and repetitive. Tidy code by moving it into functions. In Framework, a function that returns a DOM element is called a _component_.

To turn the chart above into a component, wrap it in a function and promote the `data` to a required argument. Accept any named options (such as `width`) as an optional second argument with destructuring.

Expand Down Expand Up @@ -486,6 +497,14 @@ Or with Yarn:

<pre data-copy>yarn build</pre>

Or with Pnpm:

<pre data-copy>pnpm build</pre>

Or with Bun

<pre data-copy>bun run build</pre>

The <code>build</code> command generates the `dist` directory; you can then upload this directory to your preferred hosting provider or copy it to your static site server for self-hosting. To preview your built app locally, you can use a local static HTTP server such as [http-server](https://github.com/http-party/http-server):

<pre data-copy>npx http-server dist</pre>
Expand Down
29 changes: 27 additions & 2 deletions src/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export async function create(effects: CreateEffects = defaultEffects): Promise<v
options: [
{value: "npm", label: "Yes, via npm", hint: "recommended"},
{value: "yarn", label: "Yes, via yarn", hint: "recommended"},
{value: "pnpm", label: "Yes, via pnpm", hint: "recommended"},
{value: "bun", label: "Yes, via bun", hint: "recommended"},
{value: null, label: "No"}
],
initialValue: inferPackageManager("npm")
Expand All @@ -92,8 +94,27 @@ export async function create(effects: CreateEffects = defaultEffects): Promise<v
s.start("Copying template files");
const template = includeSampleFiles ? "default" : "empty";
const templateDir = op.resolve(fileURLToPath(import.meta.url), "..", "..", "templates", template);
const runCommand = packageManager === "yarn" ? "yarn" : `${packageManager ?? "npm"} run`;
const installCommand = `${packageManager ?? "npm"} install`;
const runCommand =
packageManager === "npm"
? "npm run"
: packageManager === "yarn"
? "yarn"
: packageManager === "pnpm"
? "pnpm"
: packageManager === "bun"
? "bun"
: "npm run";
const installCommand =
packageManager === "npm"
? "npm install"
: packageManager === "yarn"
? "yarn install"
: packageManager === "pnpm"
? "pnpm install"
: packageManager === "bun"
? "bun install"
: "npm install";

await effects.sleep(1000); // this step is fast; give the spinner a chance to show
await recursiveCopyTemplate(
templateDir,
Expand All @@ -111,6 +132,9 @@ export async function create(effects: CreateEffects = defaultEffects): Promise<v
if (packageManager) {
s.message(`Installing dependencies via ${packageManager}`);
if (packageManager === "yarn") await writeFile(join(rootPath, "yarn.lock"), "");
if (packageManager === "pnpm") await writeFile(join(rootPath, "pnpm-lock.yaml"), "");
if (packageManager === "bun") await writeFile(join(rootPath, "bun.lock"), "");

await promisify(exec)(installCommand, {cwd: rootPath});
}
if (initializeGit) {
Expand All @@ -137,6 +161,7 @@ export async function create(effects: CreateEffects = defaultEffects): Promise<v
if (spinning) s.stop("Installed! 🎉");
const instructions: string[] = [];
if (rootPath !== ".") instructions.push(`cd ${rootPath}`);
if (packageManager === "pnpm") instructions.push("pnpm approve-builds");
if (!packageManager) instructions.push(installCommand);
instructions.push(`${runCommand} dev`);
clack.note(instructions.map((line) => reset(cyan(line))).join("\n"), "Next steps…");
Expand Down