vitejs / vite

Next generation frontend tooling. It's fast!
http://vite.dev
MIT License
67.98k stars 6.12k forks source link

Unnecessary errors for public js libs in index.html #15354

Closed grandsong closed 10 months ago

grandsong commented 10 months ago

Describe the bug

After migrating from Vite 4.x to 5.0.8, for dev server, whenever the page (index.html) loads, in terminal I get errors like:

09:12:55 [vite] Pre-transform error: Failed to load url /pixi.min@7.3.1.js (resolved id: /pixi.min@7.3.1.js). This file is in /public and will be copied as-is during build without going through the plugin transforms, and therefore should not be imported from source code. It can only be referenced via HTML tags.

I have 'pixi.min@7.3.1.js' in the '/public' folder and <script src="/pixi.min@7.3.1.js"></script> in the 'index.html'.

Exactly as the message suggests: 'It can only be referenced via HTML tags.'

The program in browser actually runs without any error, as well as before (at Vite 4).

Such error messages in terminal is unnecessary and very very annoying!

I know "Assets in public cannot be imported from JavaScript."

I do not "import" pixi.js. I just use it as a lib so that a global variable PIXI is defined for my code to access.

I guess the error message is a new feature in Vite 5 to warn some ignorant developers against misuse of modules which should not be in '/public' folder.

However, my practice is not a mistake. I have good reasons to do so instead of importing 'pixi.js' as a normal NPM module.

Note: There is a similar issue #14181 which however was automatically closed due to absence of minimal reproduction.

Why don't others encounter this issue?

Unlike most people, I dynamically define the option base in 'vite.config.ts':

export default defineConfig(async ({ mode }) => {
const base = '/some/path/based/on/mode' // Just for example. It actually is dynamical.
    return {
        base,
        // ...
    }
}

In this way, the entry URL of the web site is like 'http://localhost:3333/some/path/based/on/mode/'.

In my 'package.json', there are three mode for building.

{
        "build:root": "vite build --mode root",
        "build:test": "vite build --mode test",
        "build:prod": "vite build --mode prod",
}

In my company, part of the standard development process is:

1) Commit repo with branch 'test' 2) Build and get something like 'https://cdn-my.company.com/test/project-name/index.html' 3) Our QA team tests it 4) Merge changes from 'test' into branch 'prod' 5) Build and get something like 'https://cdn-my.company.com/prod/project-name/index.html' 6) Our QA team tests it

Is there a work around?

Yes.

let base: string
if (mode === 'development') {
    // Keep `base` undefined to avoid error messages like:
    // Pre-transform error: Failed to load url /pixi.min@7.3.1.js (resolved id: /pixi.min@7.3.1.js). This file is in /public and will be copied as-is during build without going through the plugin transforms, and therefore should not be imported from source code. It can only be referenced via HTML tags.
} else if (mode === 'root') {
    base = '/'
} else {
    base = `/${mode_dir_part}/${project_dir_part}/` // my real code
}

When in 'development' mode, namely using dev server, an undefined base can still allow entry from 'http://localhost:3333/some/path/based/on/mode/' while any other path in this domain works as well...

And now the error messages are gone.

What solution do I suggest?

Ideally, the dev server can smartly recognize that the js libs are indeed 'referenced via HTML tags', whereupon skip the warning. Just like when base is undefined.

Or at least, add a config option for me to purposely mute the warning for good.

Where is the code for this error message?

In 'packages\vite\src\node\server\transformRequest.ts'

async function loadAndTransform(
  //...
){
  // ....
  if (code == null) {
    const isPublicFile = checkPublicFile(url, config)
    let publicDirName = path.relative(config.root, config.publicDir)
    if (publicDirName[0] !== '.') publicDirName = '/' + publicDirName
    const msg = isPublicFile
      ? `This file is in ${publicDirName} and will be copied as-is during ` +
        `build without going through the plugin transforms, and therefore ` +
        `should not be imported from source code. It can only be referenced ` +
        `via HTML tags.`
      : `Does the file exist?`
  }
}

Why not as a normal NPM module?

I tried.

When building, if only a single js file is bundled into, it will be too big (more than 2.5Mb). And codes would grow and grow in the future.

So I use the API build.roolupOptions.outpu.manualChunks to split codes into small chunks.

After I update my repo, I want the requests for changed files from the browser of each end user to be minimal (with browser cache and CDN, unchanged files take very little request costs).

My policy is:

However, there are too many chuncks from node_modules.

I managed to combine some (for example, 'vue' and '@vue' into just 'vue') but still quite a few stay.

Many tiny chunks are a waste of http requests and thus should be avoided.

The key for a good result is balance between the number of files and coverage of decoupling.

I found that more than half of my tiny chunks are dependencies of 'pixi.js' and 'pixi-spine'.

Besides, building time is increased for the these two large modules.

So I replaced them with public lib counterparts and had been very satisfied.

... until I migrated to Vite 5 and be ambushed by the annoying warning messages.

Reproduction

https://stackblitz.com/edit/vitejs-vite-eg4ypm?file=index.html

Steps to reproduce

  1. Open a terminal
  2. Run pnpm dev
  3. Load the index.html
  4. See the message in the terminal

System Info

System:
    OS: Windows 10 10.0.19045
    CPU: (12) x64 Intel(R) Core(TM) i5-10400 CPU @ 2.90GHz
    Memory: 1.76 GB / 15.84 GB
  Binaries:
    Node: 20.10.0 - C:\Env\node\node.EXE
    npm: 9.1.2 - C:\Env\node\npm.CMD
    pnpm: 8.10.0 - ~\AppData\Local\pnpm\pnpm.CMD
  Browsers:
    Edge: Spartan (44.19041.3636.0), Chromium (120.0.2210.61)
    Internet Explorer: 11.0.19041.3636
  npmPackages:
    @vitejs/plugin-vue: ^4.5.2 => 4.5.2
    vite: ^5.0.8 => 5.0.8

Used Package Manager

pnpm

Logs

  VITE v5.0.8  ready in 2812 ms

  ➜  Local:   http://localhost:3333/dev/cms/dd/
  ➜  Network: http://10.66.32.243:3333/dev/cms/dd/
  ➜  press h + enter to show help
11:04:32 [vite] Pre-transform error: Failed to load url /pixi.min@7.3.1.js (resolved id: /pixi.min@7.3.1.js). This file is in /public and will be copied as-is during build without going through the plugin transforms, and therefore should not be imported from source code. It can only be referenced via HTML tags.
11:04:32 [vite] Pre-transform error: Failed to load url /pixi-spine@4.0.4.js (resolved id: /pixi-spine@4.0.4.js). This file is in /public and will be copied as-is during build without going through the plugin transforms, and therefore should not be imported from source code. It can only be referenced via HTML tags.

Validations

stackblitz[bot] commented 10 months ago

Fix this issue in StackBlitz Codeflow Start a new pull request in StackBlitz Codeflow.

grandsong commented 10 months ago

I digged for the option base and found a workaround. Still, this is an issue introduced by Vite 5. It needs to be fixed.

WangJincheng4869 commented 10 months ago

我也遇到了这个问题,请问如何屏蔽这个错误。这并不是错误,并且在 5.0.7 版本之前也没有这个错误,是从 5.0.8 开始出现此错误!!!

fabien-thebaud-ariadnext commented 10 months ago

I'm experiencing exactly the same issue on one of my projects (React + TS). It appeared after upgrading from vite 4.4.9 to vite 5.0.10. I'm also using a custom base:

// vite.config.ts
export default defineConfig({
  plugins: [react()],
  base: '/web/',

And I'm importing a small .js file that contains global configuration variables:

// index.html
<script src="/config.js"></script>

Every time I reload a page with the dev server, I get this misleading error message:

[vite] Pre-transform error: Failed to load url /config.js (resolved id: /config.js). This file is in /public and will be copied as-is during build without going through the plugin transforms, and therefore should not be imported from source code. It can only be referenced via HTML tags.

WangJincheng4869 commented 9 months ago

@bluwy May I ask, in which version will this issue be fixed?

bluwy commented 9 months ago

It's not released yet. But I think we'll cut another patch that includes this fix this week before starting the next Vite minor next week.