Skip to content
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

Inline file in bundle with fs.readFileSync not working with TypeScript #1736

Closed
alexharri opened this issue Jul 15, 2018 · 15 comments
Closed

Comments

@alexharri
Copy link

alexharri commented Jul 15, 2018

🐛 bug report

Parcel provides inline asset importing via statically analyzable fs.readFileSync statements. They work as expected in JavaScript but not Typescript.

🎛 Configuration (.babelrc, package.json, cli command)

package.json

{
  "scripts": {
    "start": "parcel index.html"
  },
  "dependencies": {
    "parcel": "^1.9.6"
  },
  "devDependencies": {
    "@types/node": "^10.5.2",
    "typescript": "^2.9.2"
  }
}

No custom .babelrc file

🤔 Expected Behavior

A statically analyzable fs.readFileSync statement should inline the file in the bundle, both in .js and .ts files.

😯 Current Behavior

fs.readFileSync statements are inlined in .js files but aren't in .ts files.

Output from console (see code sample)

Console output

index.ts:5 Uncaught TypeError: fs_1.default.readFileSync is not a function
    at Object.parcelRequire.index.ts.fs (index.ts:5)
    at newRequire (2.0d1d60a5.js:48)
    at parcelRequire...\node_modules\parcel\src\builtins\_empty.js (2.0d1d60a5.js:80)
    at 2.0d1d60a5.js:106
parcelRequire.index.ts.fs @ index.ts:5
newRequire @ 2.0d1d60a5.js:48
parcelRequire...\node_modules\parcel\src\builtins\_empty.js @ 2.0d1d60a5.js:80
(anonymous) @ 2.0d1d60a5.js:106

💁 Possible Solution

Implement inline file imports in .ts files.

🔦 Context

I was working with WebGL and writing shaders. Writing them with template strings didn't give me any syntax highlighting so I wanted to write them as .frag and .vert files. I expected to be able to import them easily with Parcel but received the above error. After a bit of head-scratching I realized it was a Parcel + TypeScript problem and made a repro.

There's a fairly simple workaround this issue, which is just creating a .js file which imports the desired file, for example.

// index.ts

import textFile from "./textFile.js";

// Do stuff with the text file.
// textFile.js

import fs from "fs";

const textFile = fs.readFileSync(__dirname + "/textFile.txt", "utf8");

export default textFile;

It works but could create a lot of noise if using a lot of inline assets.

💻 Code Sample

Repo with code to reproduce the issue.

🌍 Your Environment

Software Version(s)
Parcel 1.9.6
Node 8.9.1
npm/Yarn npm 6.1.0
Operating System Windows 7
@ishaantaylor
Copy link

ishaantaylor commented Sep 7, 2018

I'm having the same problem. Has anybody found a temporary workaround?

@alexharri
Copy link
Author

@ishaantaylor I showed a possible workaround in the Context section of the issue, should work if allowJs is enabled in the tsconfig.

@hasparus
Copy link
Contributor

hasparus commented Sep 22, 2018

async transform() {
if (this.options.target === 'browser') {
if (this.dependencies.has('fs') && FS_RE.test(this.contents)) {
// Check if we should ignore fs calls
// See https://github.com/defunctzombie/node-browser-resolve#skip
let pkg = await this.getPackage();
let ignore = pkg && pkg.browser && pkg.browser.fs === false;
if (!ignore) {
await this.parseIfNeeded();
this.traverse(fsVisitor);
}

There is a regex in JSAsset that launches FSVisitor.
So my intuition (I'm researching it for like 5 minutes, so I might be wrong) is we should add transform method override to TSAsset and launch FSVisitor from there.

Disregard what's above.
I've added test(#2046) to my fork of parcel, got really surprised that it works and made a reproduction repo.

Named import works fine for me and all of the imports work on CodeSandbox 😮 .

import { readFileSync } from 'fs';
const raw = readFileSync(__dirname + '/raw.tsx', 'utf-8');

DeMoorJasper pushed a commit that referenced this issue Sep 25, 2018
---
name: Add test to fs.readFileSync in TypeScript files
---
```
parcel-bundler version 1.9.7
```

## 💥 Problem

Inlining file in browser mode doesn't work in TypeScript files when `fs` is imported with star import or default import. The only way to use `readFileSync` is:
```typescript
import { readFileSync } from 'fs';
const raw = readFileSync(__dirname + '/raw.tsx', 'utf-8');
```

### Reproduction: 
Repo: https://github.com/hasparus/parcel-readfilesync-typescript-repro
ghPages: https://hasparus.github.io/parcel-readfilesync-typescript-repro/
CodeSandbox: https://codesandbox.io/s/github/hasparus/parcel-readfilesync-typescript-repro/tree/master/

Fun Fact: All ways to import `fs` work on CodeSandbox (parcel template).

## ↪️ Pull Request
Adds test to `fs.readFileSync` in TypeScript files and thus provides better workaround for #1736.

## ✔️ PR Todo
- [X] Link in #1736.
- [X] Post reproduction to CodeSandbox.
- [ ] Document how to use `readFileSync` in TypeScript?
devongovett pushed a commit that referenced this issue Oct 15, 2018
---
name: Add test to fs.readFileSync in TypeScript files
---
```
parcel-bundler version 1.9.7
```

## 💥 Problem

Inlining file in browser mode doesn't work in TypeScript files when `fs` is imported with star import or default import. The only way to use `readFileSync` is:
```typescript
import { readFileSync } from 'fs';
const raw = readFileSync(__dirname + '/raw.tsx', 'utf-8');
```

### Reproduction: 
Repo: https://github.com/hasparus/parcel-readfilesync-typescript-repro
ghPages: https://hasparus.github.io/parcel-readfilesync-typescript-repro/
CodeSandbox: https://codesandbox.io/s/github/hasparus/parcel-readfilesync-typescript-repro/tree/master/

Fun Fact: All ways to import `fs` work on CodeSandbox (parcel template).

## ↪️ Pull Request
Adds test to `fs.readFileSync` in TypeScript files and thus provides better workaround for #1736.

## ✔️ PR Todo
- [X] Link in #1736.
- [X] Post reproduction to CodeSandbox.
- [ ] Document how to use `readFileSync` in TypeScript?
devongovett pushed a commit that referenced this issue Oct 15, 2018
---
name: Add test to fs.readFileSync in TypeScript files
---
```
parcel-bundler version 1.9.7
```

## 💥 Problem

Inlining file in browser mode doesn't work in TypeScript files when `fs` is imported with star import or default import. The only way to use `readFileSync` is:
```typescript
import { readFileSync } from 'fs';
const raw = readFileSync(__dirname + '/raw.tsx', 'utf-8');
```

### Reproduction: 
Repo: https://github.com/hasparus/parcel-readfilesync-typescript-repro
ghPages: https://hasparus.github.io/parcel-readfilesync-typescript-repro/
CodeSandbox: https://codesandbox.io/s/github/hasparus/parcel-readfilesync-typescript-repro/tree/master/

Fun Fact: All ways to import `fs` work on CodeSandbox (parcel template).

## ↪️ Pull Request
Adds test to `fs.readFileSync` in TypeScript files and thus provides better workaround for #1736.

## ✔️ PR Todo
- [X] Link in #1736.
- [X] Post reproduction to CodeSandbox.
- [ ] Document how to use `readFileSync` in TypeScript?
@figalex
Copy link

figalex commented Oct 16, 2018

Is there another issue to support transforming this readFileSync when not using named imports?

Is weird that we can do fs.readFileSync() in .js files but not in .ts/.tsx files.

@Prashant-Kan
Copy link

Hello Guys,
I am facing a similar problem
I have imported "fs" using import * as fs from "fs" and trying to execute fs.readFile() and fs.readFileSync with there respective arguments.
But, getting an error as "fs" object doesn't have a function readFile() and readFileSync().
I have tried using var fsFile = require("fs");.

I am using in Cypress automation project in typescript.

@uglycoyote
Copy link

uglycoyote commented May 18, 2019

I'm running into this issue trying to use the adl-xapiwrapper library with Typescript, using import ADL from 'adl-xapiwrapper'. The actual fs.readFileSync call is several layers of require statements down from adl-xapiwrapper, in mime.js. Here's the callstack where I get the fs.readFileSync is not a function error. This is parcel version 1.11.0

Mime.load (mime.js:54)
parcelRequire.../node_modules/mime/mime.js.path (mime.js:90)
newRequire (src.f69400ca.js:49)
localRequire (src.f69400ca.js:55)
parcelRequire.../node_modules/request/request.js.http (request.js:16)
newRequire (src.f69400ca.js:49)
localRequire (src.f69400ca.js:55)
parcelRequire.../node_modules/request/index.js.cookie-jar (index.js:20)
newRequire (src.f69400ca.js:49)
localRequire (src.f69400ca.js:55)
parcelRequire.../node_modules/adl-xapiwrapper/lib/adl-xapiwrapper.js.request (adl-xapiwrapper.js:11)
newRequire (src.f69400ca.js:49)
localRequire (src.f69400ca.js:55)
parcelRequire.index.tsx.react (index.tsx:11)
newRequire (src.f69400ca.js:49)
(anonymous) (src.f69400ca.js:81)
(anonymous) (src.f69400ca.js:107)

Edit: not quite sure this is the same bug, I'm actually getting this just with a plain js file trying to import adl-xapiwrapper, perhaps I'll make a separate issue for it.

@felixfbecker
Copy link

I have the same problem, even with named imports it does not get inlined.

Input:

export async function setSchema(dgraphClient: DgraphClient): Promise<void> {
    // This gets bundled by Parcel
    const schema = readFileSync(__dirname + '/../dgraph.schema', 'utf-8')
    const op = new Operation()
    op.setSchema(schema)
    await dgraphClient.alter(op)
}

Output:

async function setSchema(dgraphClient) {
  // This gets bundled by Parcel
  const schema = fs_1.readFileSync(__dirname + '/../dgraph.schema', 'utf-8');
  const op = new dgraph_js_1.Operation();
  op.setSchema(schema);
  await dgraphClient.alter(op);
}

@mischnic
Copy link
Member

@felixfbecker

I have the same problem, even with named imports it does not get inlined.

Could you please share your tsconfig or a complete reproduction?
Works for me with this typescript:

import { readFileSync } from "fs";

export function setSchema() {
	const schema = readFileSync(__dirname + "/test.schema", "utf-8");
	console.log(schema);
}

@github-actions
Copy link

github-actions bot commented Feb 7, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs.

@bibek-stripe
Copy link

Working with Parcel 2.4.1 and this seems like it's still happening. Would it make sense to reopen the issue?

@github-actions github-actions bot removed the Stale Inactive issues label May 9, 2022
@spion
Copy link

spion commented Aug 24, 2022

Can someone reopen this? How does it get closed?

@mischnic
Copy link
Member

@bibek-stripe @spion Can you provide a reproduction? When I tried it in #1736 (comment), it worked fine

@spion
Copy link

spion commented Aug 24, 2022

Sorry, never mind - looks like this is a different issue - its the use of template strings that doesn't work:

fs.readFileSync(`${__dirname}/path/to/file.txt`)

is simply not recognized.

@juanmirocks
Copy link

In Parcel 2, the currently recommend way to read a file as literal, plain text is using the bundle-text: scheme, as in:

import text from 'bundle-text:./myFile';
console.log(text);

@caedes
Copy link

caedes commented Oct 20, 2023

Hello!👋

First, I encountered the same exact issue; fs.writeFile doesn't work within .ts files.

Then, I update my package.json just using:

{
  "source": "src/create-projects.ts",
  "main": "dist/create-projects.js",
  "type": "module",
}

And voilà ! I can parcel build and run a node dist/create-projects.js to create my file.

I hope this can help you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests