oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
https://bun.sh
Other
73.25k stars 2.69k forks source link

`bun build` removes `"use strict"`, `"use client"`, `"use server"`, etc. directives #6854

Open ctjlewis opened 10 months ago

ctjlewis commented 10 months ago

What version of Bun is running?

1.0.7+b0393fba6200d8573f3433fb0af258a0e33ac157

What platform is your computer?

Darwin 23.1.0 arm64 arm

What steps can reproduce the bug?

Screenshot 2023-11-02 at 4 16 20 AM

Leading string removed by bun build and Bun.build(...):

$ bun build test.ts
  // test.ts
  console.log(123);

What is the expected behavior?

Without --minify, this string shouldn't be removed.

What do you see instead?

The string is removed.

Additional information

No response

ctjlewis commented 10 months ago

Manually forcing "use client" directives in build output:

/// <reference types="bun-types" />
import { glob } from "glob"

const entrypoints = await glob("lib/**/*.{js,jsx,ts,tsx}")
const { outputs } = await Bun.build({
  entrypoints,
  format: 'esm',
  outdir: './dist',
  external: ['react', 'react-dom'],
  minify: false,
})

for (const output of outputs) {
  const bytes = await output.arrayBuffer()
  const prefix = '"use client"\n\n'
  await Bun.write(output.path, [prefix, bytes])
}
Bessonov commented 10 months ago

Please check the latest bun release: https://bun.sh/blog/bun-v1.0.12#fixed-transpiler-preserves-custom-directives

ctjlewis commented 10 months ago

fixed by #7027

ctjlewis commented 10 months ago

Shit, there's an edge case we didn't think of, I closed without verifying.

It's not enough to just not remove these directives - we have to hoist them, and make sure they're the first expressions in the emitted AST.

For instance, we have to make sure JSX runtime imports and inlined dependencies are added after the directive.

Repro (1.0.14): JSX runtime imports

$ bun build --no-bundle lib/components/form.tsx 
import {
jsxDEV
} from "react/jsx-dev-runtime";
"use client"; // <---
// ...

Repro (1.0.14): Inlined imports

$ bun build lib/components/form.tsx
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getProtoOf = Object.getPrototypeOf;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
// ...
"use client"; // <---
// ...

cc @Jarred-Sumner

ctjlewis commented 10 months ago

Lmfao, I tagged Jared instead of Jarred. My bad Palmer!

Ant59 commented 2 months ago

Still an issue in 1.1.17. Bundling a directory of React components with "use client"; directives results in an output file with many directives throughout instead of one hoisted to the top.

Ant59 commented 2 months ago

Next.js outright refuses to load any component from the output due to the directive placement.

× The "use client" directive must be placed before other expressions. Move it to the top of the file to resolve this issue.

dgpt commented 1 month ago

+1 I'm currently experiencing this issue with the react-error-boundary library. When I build with bun it sticks the 'use client' in the middle of the compiled code and I get Error: × The "use client" directive must be placed before other expressions. Move it to the top of the file to resolve this issue.

edit: I'm also getting this with when building a library that imports from @mui...