parcel-bundler / parcel

The zero configuration build tool for the web. 📦🚀
https://parceljs.org
MIT License
43.5k stars 2.27k forks source link

[RFC] A way to include stylesheets/scripts in html without bundling them #1087

Open samsch opened 6 years ago

samsch commented 6 years ago

RFC

Right now, Parcel will attempt to bundle all files referenced in <link href=""/> or <script src=""> tags in your html.

I think it would be useful to have a way to have Parcel ignore some linked files. Specifically, cases where you are building or otherwise sourcing stylesheets separately from your Parcel build, but served from the same folder (or folder tree) as the bundled files. (Files served from other domains or referenced with https:// are already ignored.)

💁 Possible Solution

A possibly naive solution might be to add an identifying character (such as a "#") to the start of any paths/files Parcel should ignore, e.g.:

<html>
  <head>
    <link href="#/bootstrap.css" />
  </head>
</html>

Parcel would simply strip the "#" out when building.

Another possible solution would be ignore comments:

<html>
  <head>
    <!-- parcel-ignore -->
    <link href="/bootstrap.css" />
    <!-- parcel-ignore-end -->
  </head>
</html>

I really don't have an opinion on the specific identifying character or comment format, these were just the first that I thought of to get the idea down.

🔦 Context

I came across this situation while attempting to work around using bootstrap.scss in a project with css-modules. More on that here. However, another reason might be needing to share a local stylesheet between the front and backend, and have it cache for both. You might do this if you have something like a custom Bootstrap build used on all pages (mostly rendered by the backend), including just a single page built with Parcel.

fathyb commented 6 years ago

I really like the #/ syntax proposal, it's clean and easy to parse 👍.

juank11memphis commented 6 years ago

I like this, I think it would be super useful

teabyii commented 6 years ago

A way to have Parcel ignore some linked files is needed.

However, I don't think it is a good way to add info in HTML files for this. Just keep HTML for you business, without anything for building.

Consider other ways,maybe:

  1. Add .parcelignore to tell parcel to ignore some paths
  2. Add option for this,like --ignore <path> or parcel: { ignore: [] } in package.json
Joe-Withey commented 5 years ago

I had a need to ignore some script tags that were pointing the absolute path and found this issue. For anyone looking to solve this problem I created a plugin, it allows for the use of the # prefix as described above.

https://github.com/Joe-Withey/parcel-plugin-html-root-syntax

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 30 days if no further activity occurs. Thank you for your contributions.

RussCoder commented 4 years ago

@Joe-Withey

The plugin doesn't work for me (with parcel 1.12.4), there is an error:

‼ Plugin parcel-plugin-change-file failed to initialize: ReferenceError: configFilePath is not defined

For my need, I found the following solution:

Instead of

<link rel="icon" href="/favicon.png">

I write

<script>document.write(`<link rel="icon" href="/favicon.png">`)</script>

Not good, but works.

samsch commented 4 years ago

Could a member/author close either this issue with wontfix or add it a roadmap, and maybe add a comment for whether this feature will exist in v2?

mischnic commented 4 years ago

I think something like <link href="/bootstrap.css" data-parcel-ignore/> (the attribute would be removed by Parcel) or

<script data-parcel-ignore>
     // ...
</script>

would make sense

VladimirMikulic commented 3 years ago

I've made a plugin that excludes assets from bundling in Parcel 2. Check it out https://www.npmjs.com/package/parcel-resolver-ignore

  1. npm i parcel-resolver-ignore -D
  2. .parcelrc
    {
    "extends": "@parcel/config-default",
    "resolvers": ["parcel-resolver-ignore", "..."]
    }
  3. package.json
    {
    "parcelIgnore": [
    "bootstrap.css"
    ]
    }

Good to go! No need to modify source files! Let me all know what you think!

fregante commented 3 years ago

Since there's a similar example above, here's a solution for who wants to include favicon.ico without changing its name:

How to copy favicon.ico with Parcel 2

  1. Don't include the favicon meta tag in your HTML
  2. Add favicon.ico to the list of entry points:
parcel build index.html favicon.ico
  1. Set a raw transformer for the favicon.ico
    {
    "extends": "@parcel/config-default",
    "transformers": {
    "favicon.ico": ["@parcel/transformer-raw"]
    }
    }

And voilà:

✨ Built in 2.30s

dist/index.html                         33.65 KB    396ms
dist/index.90c1f53b.css                  5.79 KB    1.45s
dist/index.2ee6019c.js                    1.4 KB    157ms
dist/favicon.ico                         2.37 KB    143ms
fregante commented 3 years ago

@mischnic I think a more generic solution is to use comments:

<!-- parcel-ignore -->
<script src="some-static-file.js"></script>

<!-- parcel-ignore -->
<link href="bootstrap.css"></script>

<!-- parcel-ignore -->
<iframe src="../status.php"></iframe>

But also:

/* parcel-ignore */
@import '/some-external-file.css';

html {
    background: papayawhip;
}
/* parcel-ignore */
import('../my-local-file.js');

console.log('Loading from server');
marcysutton commented 2 years ago

Really glad I found this issue, as Parcel was having trouble with an HTML5 video source element despite saying videos are supported. I kept getting an error about "No transformer found for mp4" files. This worked in case anyone else lands here:

{
  "extends": "@parcel/config-default",
  "transformers": {
    "*.mp4": ["@parcel/transformer-raw"]
  }
}
fregante commented 2 years ago

I've probably been waiting for a solution to this since the early days of Parcel. There is a number of reasons why I'd want a specific URL to be ignored by Parcel (i.e. left untouched) but there isn't.

Today's attempt was to have Parcel ignore a call to a "local" dynamic API endpoint, like /api/do-something but I just can't do it. The closest I can come is a ridiculous use of form, which is not advised 😅

- <a href="/api/do-something">Do</a>
+ <form action="/api/do-something" method="get"><button>Do</button></form>

I'm glad that parcel-resolver-ignore exists, which works in this case, but for more dynamic URLs they'd need to be set every time in the configuration rather than inline, which means they might get out of sync.

jdanyow commented 1 year ago

I recently encountered an issue where a third-party javascript dependency wouldn't parcel build correctly in production. The file output seemed to be mangled incorrectly by @parcel/optimizer-swc, resulting in duplicate variable declarations and errors at runtime.

The file causing this issue had already been minified by the library maintainer. I really didn't need parcel to make any transforms, just copy the raw file to the dist folder.

After a bit of digging, it turned out to be pretty easy to configure a raw: named pipeline. I got the idea from the config in pr 7050. Depending on your use-case, you may only need a subset of the transformers/packagers/optimizers sections below.

{
  "extends": "@parcel/config-default",
  "transformers": {
    "raw:*": [
      "@parcel/transformer-raw"
    ]
  },
  "packagers": {
    "raw:*": "@parcel/packager-raw"
  },
  "optimizers": {
    "raw:*": []
  }
}

This allows you to reference json, scripts, etc without changing them.

<html>
  <head>
    <link rel="preload" href="raw:emoji.json" as="fetch" />
    <script src="raw:./a/b/c.js"></script>
    ...

Hopefully this helps others. We could create a shared configuration distributed on npm if folks think this is a good way of handling this type of issue.