94319


##### 質問内容

提示コードのスクリプト部ですがfetch関数を使ってテキストファイルの中身を表示させたいのですが正しいパスを指定してもなぜか実行時のエントリーポイントのindex.htmlの中身が表示されてしまうのですがこれはなぜでしょうか？原因がわかりません。

##### 試したこと

1,`tsc script/Main.ts`を実行して`npx paracel index.html --open`を実行  
2,提示コードのようにファイルパスの間違えを疑いいくつかのパスで実行

##### 参考サイト

fetch(テキストファイルを読み込む 見出し部): <https://gray-code.com/javascript/load-file-with-
fetch-api/#section2>

##### 環境

OS: windows10  
言語: TypeScriopt

##### テキストファイル内容

[code]

    attribute vec4 aVertexPosition; //
    
    uniform mat4 uProjectionMatrix; //
    
    uniform mat4 uPosition; //
    uniform mat4 uScale;    //
    uniform mat4 uRotate;   //
    
    void main() 
    {
    
        mat4 model = uPosition * uRotate * uScale;      //
    
        gl_Position = (uProjectionMatrix * model) * aVertexPosition;
    }
    
    
[/code]

##### コンソール

[code]

    <!DOCTYPE html>
    <html lang="ja">
           <head>
                <meta charset="utf-8">
                <title>テスト</title>
                <link rel="stylesheet" type="text/css" href="/style.e308ff8e.css">
           <script src="/style.e308ff8e.js"></script></head> 
    
           <body>
    
            <!-- スクリプト -->
            
            <canvas id="glCanvas" width="640" height="480"></canvas>
    
            <script src="/Main.ddd9b095.js" type="module"></script>
    
           </body>
    
    </html>
    
    Main.ts:4 <!DOCTYPE html>
    <html lang="ja">
           <head>
                <meta charset="utf-8">
                <title>テスト</title>
                <link rel="stylesheet" type="text/css" href="/style.e308ff8e.css">
           <script src="/style.e308ff8e.js"></script></head> 
    
           <body>
    
            <!-- スクリプト -->
            
            <canvas id="glCanvas" width="640" height="480"></canvas>
    
            <script src="/Main.ddd9b095.js" type="module"></script>
    
           </body>
    
    </html>
    
    
[/code]

##### script.ts

[code]

    //fetch("../asset/shader/BasicColor.vert").then((res)=>{return res.text();}).then((data) =>{ console.log(data); });
    fetch("asset/BasicColor.vert").then((res)=>{return res.text();}).then((data) =>{ console.log(data); });
    fetch("asset/shader/BasicColor.vert").then((res)=>{return res.text();}).then((data) =>{ console.log(data); });
    
    
[/code]


CC BY-SA 4.0
2023-03-25T13:33:40.263
94315
2023-03-26T17:19:08.977
2023-03-26T17:19:08.977
-1
55177
question
typescript parceljs
fetch関数を使ってテキストファイルの中身を表示するとなぜかindex.htmlの中身が表示される原因が知りたい。


Parcelのビルド(build)や開発サーバー(serve)では、次のファイルしか生成や公開の対象になりません。

  * エントリーポイントとして指定された各ファイル
  * エントリーポイントから再帰的に読み込まれる各ファイル、読み込まれる例は下記を参照 
    * HTML等での`src`や`href`属性等を用いて読み込まれれたりリンクが張ってあるHTML、CSS、JavaScript、画像等のファイル
    * CSS等での`@import`や`url()`による読み込み
    * JavaScript等での`import`または`require`による読み込みや、`URL`コンストラクターによるURL取得

ビルドした場合、上記のファイル以外はdist内に作成されません(CSSやJavaScript等は一つにまとめられたり、名前にハッシュ値が追加されたり※、mapファイルも付けてあったりします)。開発サーバーも同じで、このdistで作成されるファイル以外は公開されません(アクセスできません)。開発サーバーで存在しないファイルにアクセスした場合、ルートドキュメント(`http://localhost:1234/`でアクセスしたときのドキュメント)を返すようになっています。

※
エントリーポイントであるHTML以外は名前にハッシュ値が追加され、元々の名前ではアクセスできない場合があることに注意してください。たとえば、"main.js"というJavaScriptはビルドや開発サーバー上では"main.a1b3c5d7f.js"と言う風に名前にハッシュ値が追加されます。HTML内でのパスはこのハッシュ値がついた名前に自動的に置換されます。

では、エントリーから再帰的に読み込まれないファイルもビルドの生成物や開発サーバーでの公開ファイルにに含めたい場合はどうすればいいのかですが、[URL
dependencies](https://parceljs.org/languages/javascript/#url-
dependencies)の機能を使う方法が公式のようです。

* * *

実際にどのようにすればいいのか実例で解説します。実際の修正内容はファイルの構成によって変わるため、解説用に質問と同じ現象が発生する状態の検証環境を用意し、それをどのように修正すると良いかを説明します。

【検証環境】  
始めにnode.jsをインストールしておきます(v18.15.0で検証)。空のディレクトリーに以下の4つのファイルを置きます。(サブディレクトリはありません)

package.json

[code]

    {
      "devDependencies": {
        "parcel": "^2.8.3"
      }
    }
    
[/code]

index.html

[code]

    <!DOCTYPE html>
    <html>
    <head>
      <title>test</title>
      <script type="module" src="./main.js"></script>
    </head>
    <body>
      <p>content of sample.txt</p>
      <pre id="text"></pre>
    </body>
    </html>
    
[/code]

main.js

[code]

    // Parecl cannot support top level await, so use async IIFE.
    // https://github.com/parcel-bundler/parcel/issues/4028
    (async () => {
      const textPath = "./sample.txt";
      const response = await fetch(textPath);
      const text = await response.text();
      document.getElementById("text").textContent = text;
    })();
    
[/code]

sample.txt

[code]

    sample text
    
[/code]

各ファイルを設置したら、parcelのパッケージを取得します。

[code]

    npm install
    
[/code]

これで準備完了です。これは、"sample.txt"を`fetch`で読み込んで、その中身を表示するというものです。`fetch`で取得対象が`textPath`(その中身は"sample.txt"という文字列)であるということはわかりますよね。

では実際にうまくいくか、下記コマンドで試して見ましょう。

[code]

    npx parcel index.html --open
    
[/code]

ブラウザーが開きますが、"sample.txt"の中身では無く"index.html"の中身が表示されてしまいます。"sample.txt"はエントリーポイント("index.html")から再帰的に読み込まれていないため、開発サーバー上には存在しません。存在しないパスへのアクセスはルートドキュメント("index.html")を返すので、"index.html"の中身が表示されていると言うことです。

これを修正するには、"main.js"でURL依存を使えば良い事になります。次のように書き換えてみましょう。(変更は4行目のみです)

main.js

[code]

    // Parecl cannot support top level await, so use async IIFE.
    // https://github.com/parcel-bundler/parcel/issues/4028
    (async () => {
      const textPath = new URL("./sample.txt", import.meta.url);
      const response = await fetch(textPath);
      const text = await response.text();
      document.getElementById("text").textContent = text;
    })();
    
[/code]

今度は"sample.txt"の中身が表示されたかとも思います。`new URL("./sample.txt",
import.meta.url)`と書かれていることで、Parcelは「"./sample.txt"は必要なファイルである」と認識します。ビルドや開発サーバーでの対象となり、名前にはハッシュ値が追加され、元々の`new
URL("./sample.txt",
import.meta.url)`はそのファイルにアクセス可能なパス(アクセスすると"sample.txt"を表示するパス)の`URL`になるように書き替えられます。`fetch`は文字列でも`URL`でも受け付けられますので、書き替えられた`URL`を用いて"sample.txt"にアクセスでき、その中身が表示されるようになると言うことです。

* * *

こういった静的ファイルを扱う方法はその他にもあります。詳しくは下記のIssuesでの議論が参考にしてみてください。

<https://github.com/parcel-bundler/parcel/issues/1080>


CC BY-SA 4.0
2023-03-26T04:28:03.460
94319
2023-03-26T04:28:03.460
7347
94315
answer