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

Ignore certain link targets in HTML href #1186

Open
dobesv opened this issue Apr 14, 2018 · 37 comments
Open

Ignore certain link targets in HTML href #1186

dobesv opened this issue Apr 14, 2018 · 37 comments

Comments

@dobesv
Copy link
Contributor

dobesv commented Apr 14, 2018

🙋 feature request

🤔 Expected Behavior

It should be possible to write, for example:

<a href="/path/to/generated-report.csv">View Report</a>

And have Parcel ignore that URL (e.g. not report any error that it cannot resolve that file on disk).

In my case I have a similar URL that leads to a server-generated report. When Parcel sees the link to the report it complains.

😯 Current Behavior

Parcel will ignore absolute paths that include host, scheme, etc.. when processing HTML files.

Some work was also done to detect "virtual paths". The code currently will ignore a URL that has no . in it, or its only . is in the first position. So basically it accepts a path with no file suffix.

However, if you write a link as above, Parcel will report an error because the path is not "absolute" (it has no scheme) and it has a . in it.

💁 Possible Solution

Parcel continue to pile on assumptions about links to determine whether their target is expected to exist on disk at build time, for example ignore links with # or ? in them. This would work in my case, I guess, since I could add some of that noise to the link as a workaround. Or perhaps a custom prefix like ///.

A more robust approach would probably be preferred, though.

For example, adding a new attribute, as in <a href="/path/to/report.csv" data-parcel-ignore>View Report</a>, would allow any link to be annotated without modification and warn Parcel not to rewrite/follow that link.

Alternatively, there could be a way to specify (in an options file or on the command line) certain URL patterns which are dynamic / virtual and shouldn't be loaded by Parcel. This has some appeal because it can be applied globally rather than for every link. Users with a lot of virtual URLs can set a regular expression that excludes everything outside the specific folders that contain static resources.

🔦 Context

I am switching to Parcel from Gulp. I have a link to a dynamically generated file and Parcel is complaining that it cannot resolve the target of that link.

Note: as a workaround, I have switched to using ng-href instead of href which parcel does ignore. So, this works because I am using angular1.x.

@devongovett
Copy link
Member

I don't really want to add parcel specific things as HTML attributes.

we could just make dependencies from <a href> optional, then it would create a dependency when needed but not error if it could not resolve the file. might be harder to debug in case you messed up a legit path though. wdyt?

@dobesv
Copy link
Contributor Author

dobesv commented Apr 14, 2018 via email

@fahrradflucht
Copy link

I would oppose the <a href> based solution running into the same problem with <script src> where the src file is generated later.

@ymzuiku
Copy link

ymzuiku commented Jul 22, 2018

You can temporary way In #1719

📦 Install parcel-plugin-change-file

yarn add -D parcel-plugin-change-file

📝 Change index.html

Add <!--[ your-code ]-->

<body>
  <!--[ <a href="/path/to/generated-report.csv">View Report</a>  ]-->
</bodt>

👌 OK, jump to parcel bundler

<body>
  <a href="/path/to/generated-report.csv">View Report</a>
</bodt>

🙈 Welcome star Github parcel-plugin-change-file

@taj
Copy link

taj commented Oct 30, 2018

You can temporary way In #1719

📦 Install parcel-plugin-change-file

yarn add -D parcel-plugin-change-file

📝 Change index.html

Add <!--[ your-code ]-->

<body>
  <!--[ <a href="/path/to/generated-report.csv">View Report</a>  ]-->
</bodt>

👌 OK, jump to parcel bundler

<body>
  <a href="/path/to/generated-report.csv">View Report</a>
</bodt>

🙈 Welcome star Github parcel-plugin-change-file

Unfortunately this solution doesn't seem to work anymore. See issue

Anyone has a solution?

@chrisdmacrae
Copy link

@tajchumber https://www.npmjs.com/package/parcel-plugin-asset-fourohfour

Makes parcel throw a warning instead of an error for dependencies that can’t be resolved in HTML and CSS.

@bard
Copy link

bard commented Dec 16, 2018

@chrisdmacrae worked for me after a small fix. Please consider getting it into a repo so one can fork & PR. Thanks a lot for publishing it!

@mischnic
Copy link
Member

mischnic commented Jan 6, 2019

Is something planned regarding this for Parcel 2?

@chrisdmacrae
Copy link

@bard do you mind sharing what you issue was?

@rjyo
Copy link

rjyo commented Jan 11, 2019

I got in a similar condition where I had python template inside the href attribute.

<a href="{{ var_a }}">...</a>

Here a snippet for ignore the error and continue the build

const HTMLAsset = require('parcel-bundler/lib/assets/HTMLAsset')

function shouldIgnore (file) {
  return /{{.+}}/.test(file)
}

class SkipPythonTemplateAsset extends HTMLAsset {
  addDependency (name, opts) {
    if (!shouldIgnore(opts.resolved)) {
      return super.addDependency(name, opts)
    }
  }

  processSingleDependency (p, opts) {
    if (shouldIgnore(p)) return p
    else return super.processSingleDependency(p, opts)
  }
}

module.exports = SkipPythonTemplateAsset

If you use parcel with its API like me, the add the following to your build script.

bundler.addAssetType('html', require.resolve('./asset.js'))

Let me know whether it works. If needed I can make a plugin for that. And it should be easy to create a plugin to let the users define which kind of patterns to ignore.

@shreeve
Copy link

shreeve commented Jan 30, 2019

Also see #1719.

What about a simple way to do this by prefixing the url with an "=" to indicate an exact url that should not be processed? In effect, it's like a new alias, similar to what is done with "@" or "~", etc.

parcel 4eae6c4 2019-01-30 12-51-43

I sort of hacked StylusAsset to do this for me, but it seems like if a new "=" prefix was used, it could solve the issue?

@shreeve
Copy link

shreeve commented Jan 30, 2019

The goal of this is to be able to prefix an import with an '=' at the start of the path to tell parcel to just pass this url through without any processing. Is there a better way to do this? Some of the suggestions about seem a little heavy.

@caymard
Copy link

caymard commented Apr 15, 2019

@tajchumber https://www.npmjs.com/package/parcel-plugin-asset-fourohfour

Makes parcel throw a warning instead of an error for dependencies that can’t be resolved in HTML and CSS.

Seems to be exactly what I'm looking for, but I have the following error when npm run build-ing:

  Parser "parcel-plugin-asset-fourohfour/lib/HTML404Asset.js" failed to initialize when processing asset "index.html". Threw the following error:
Error: Cannot find module 'parcel-bundler/lib/Logger'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:582:15)
    at Function.Module._load (internal/modules/cjs/loader.js:508:25)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (/home/caymard/dev/citymeo/tizen-player/node_modules/v8-compile-cache/v8-compile-cache.js:159:20)
    at Object.<anonymous> (/home/caymard/dev/citymeo/tizen-player/node_modules/parcel-plugin-asset-fourohfour/lib/HTML404Asset.js:6:16)
    at Module._compile (/home/caymard/dev/citymeo/tizen-player/node_modules/v8-compile-cache/v8-compile-cache.js:178:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3) falling back to RawAsset

@chrisdmacrae
Copy link

@caymard

It looks like the plugin can't resolve parcel's built-in logger.

Are you sure parcel is available in your node modules and has a lib folder?

@foobarbecue
Copy link

foobarbecue commented Jul 16, 2019

@chrisdmacrae , I'm excited to use your plugin, but I have the same problem as @caymard . In node_modules/parcel-bundler I have lib but there is no Logger folder in there. Looks like the logger was separated out into another package in Parcel 2: #2134

@Charbo23
Copy link

@tajchumber
ymzuiku/parcel-plugin-change-file#1 (comment)
The perfect solution by now, a little bit late though.

@taj
Copy link

taj commented Jul 18, 2019

@Charbo23 I will have a look at it when I get a chance! :)

@foobarbecue
Copy link

foobarbecue commented Aug 7, 2019

Here's a patch to make parcel-plugin-asset-fourohfour not crash recent versions of parcel:

https://gist.github.com/foobarbecue/2ab2fb3dd40c651aa0dacf6f1582293c

but it's still replacing <link rel="stylesheet" href="/files/App.css" type="text/css"> with <link rel="stylesheet" href="/64870eb25f47455d8267d2e2fbe9fb91.css" type="text/css">

So I guess I'll try https://github.com/Joe-Withey/parcel-plugin-html-root-syntax from #1087

@minecrawler
Copy link

minecrawler commented Dec 5, 2019

none of the solutions here works, and I want to do a redirect using a nginx-routed service on the same domain and base-path... so there is definitely nothing to bundle for Parcel 😕

I really like the idea of appending paths which should not be processed with something like a =. This should not be too much trouble implementing, if it is an acceptable solution...

While others say that Parcel 2 is on the way... this ticket has been open for nearly two years, and I don't know how long it will take until its released and if it has this feature implemented, so a simple solution for Parcel 1 would be great.

@RussCoder
Copy link

@minecrawler

I agree, no one of plugins I have tried (including the plugin from here #1087 (comment)) works with parcel 1.12.4

However, 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.

@konsumer
Copy link

I have an issue that I think is related:

I am using firebase, and they have a nice local emulator for database/files/etc, and I got proxying setup with parcel:

const Bundler = require('parcel-bundler')
const express = require('express')
const { createProxyMiddleware } = require('http-proxy-middleware')
const chalk = require('chalk')

const { PORT = 1234 } = process.env

const app = express()

app.use(createProxyMiddleware('/__/', {
  target: 'http://localhost:5000/'
}))

const bundler = new Bundler('src/index.html')
app.use(bundler.middleware())

app.listen(Number(PORT))
console.log(`${chalk.yellow('Development Server:')} ${chalk.blue(chalk.underline(`http://0.0.0.0:${PORT}`))}`)

I'd like to use their pre-configured init-object, normally at /__/firebase/init.js. It's not only easier to use than tracking my own credentials, but firebase will serve up the right credentials depending on where the app is deployed, which is super-handy for dev/staging/prod.

When I hit the URL directly, it works fine, but if do this in my entry-point HTML:

<script defer src="/__/firebase/init.js"></script>

I get no such file or directory error. It would be cool if I could tell parcel to leave that URL alone.

@konsumer
Copy link

As a hacky workaround, specific to react, I can use Suspense with fetch & eval, with above proxy:

/* global fetch */

import React, { Suspense } from 'react'
import { render } from 'react-dom'
import firebase from 'firebase/app'
import { FirebaseAppProvider } from 'reactfire'

// I make it global so eval can find it
global.firebase = firebase

// this is a reusable util for Suspense + promises
function wrapPromise (promise) {
  let status = 'pending'
  let response

  const suspender = promise.then(
    (res) => {
      status = 'success'
      response = res
    },
    (err) => {
      status = 'error'
      response = err
    }
  )

  const read = () => {
    switch (status) {
      case 'pending':
        throw suspender
      case 'error':
        throw response
      default:
        return response
    }
  }

  return { read }
}

const config = wrapPromise(fetch('/__/firebase/init.js').then(r => r.text()).then(t => eval(t)))

const FirebaseProvider = (props) => (<FirebaseAppProvider firebaseConfig={config.read().options} {...props} />)

const App = () => (
  <Suspense fallback={null}>
    <FirebaseProvider>
    REST OF APP THAT USES reactfire HERE
    </FirebaseProvider>
  </Suspense>
)

render(<App />, document.getElementById('root'))

@LukeTOBrien
Copy link

Hello there,

I have come here after I have the same need.
I have a project containing Scripts and Styles that I am preparing for another project.
The other project is an ASP project and it have some .js and .css files that are pulled in from NuGet at build time.
These files are in directories starting with an underscore (_) - So like _framework or _content).

So the issue is that these directories are only created at build time by the ASP project, so when I parcel build index.html I get 404 errors.
So I need to ignore directories starting with _.

Any updates? Will this feature be in Parcel 2?

@endafarrell
Copy link

endafarrell commented Jun 2, 2020

I too need something similar. For many reasons, I cannot get all of my site into parcel (not parcel's fault) and of the options listed above I think I prefer are:

  • to leave parcel's dependency graph "as is"
  • add an optional config (uuug - goes against the zero config philosophy, but ...) that explicitly lists the paths to NOT raise an exception for when missing, that they be raised as warnings (for visibility)

There was/is #448 which might warrant another look as it could be a mechanism to achieve this.

@schmod
Copy link

schmod commented Jun 10, 2020

there's also the option for having something like:

<!-- parcel-ignore -->
  <link href="/magic.css" rel="stylesheet" type="text/css">
<!-- end-parcel-ignore -->

Alternatively, we could have some sort of .parcelignore file, enumerating files/paths that specifically should not be bundled, transpiled, or touched in any way.

@devniel
Copy link

devniel commented Aug 5, 2020

I'm getting this problem with href containing URLs to other websites. (with parcel 1)
UPDATE: I used parcel 2 and it's ok.

@damon-hall
Copy link

Is there any current solution to this? I'm trying to use parcel to bundle my cordova assets but because I need to include 'cordova.js' in my index.html it doesn't seem like I can use parcel for it?

@dobesv
Copy link
Contributor Author

dobesv commented Aug 5, 2020

@damon-hall #1186 (comment) seems the most promising of the workarounds listed so far.

It seems there's no official opinion from the parcel team how they want to handle this, so nobody has made a PR to implement any built-in mechanism,

@mischnic
Copy link
Member

mischnic commented Aug 5, 2020

Related: #1087 (comment), #357

@LukeTOBrien
Copy link

LukeTOBrien commented Aug 5, 2020 via email

@mischnic
Copy link
Member

mischnic commented Aug 5, 2020

parcel-bundler/parcel/projects/5

We don't really use Github Projects, this does not reflect our priorities.

Looking at that board though, I see Rust transformer, Kotlin transformer, Reason transformer.

We had these in Parcel 1 and are happy to accept contributions. The focus is still on Parcel core itself (to provide a platform for plugins) and of course the "traditional" bundler use case.

@davenquinn
Copy link

This is a pretty major gotcha for anyone trying to write frontend code that interfaces with outside services sharing the same domain.

I spent a while using Parcel 2 trying to find a solution to enable simple relative links in HTML such as <script src="/socket.io/socket.io.js"></script> only to be end up here. I concur with others in the thread that = may be the way to go here — but picking a direction and moving in it soon seems essential for v2.

@LukeTOBrien
Copy link

Perhaps in Parcel 2 this could be something to add to the .parcelrc? An array of ignore glob paths?

"ignore": [
    "./lib/**/*",
    "./_framework/**/*"
}

@Xeevis
Copy link

Xeevis commented Dec 22, 2020

Globs in .parcelrc would totally work for us. Parcel 2 cannot be used with Blazor WebAssembly because resources are dynamically loaded at runtime from dll libraries. This alone would open Parcel 2 to Blazor devs.

"ignore": [
    "./_framework/**/*",
    "./_content/**/*"
]

@karmanyaahm
Copy link

karmanyaahm commented Apr 11, 2021

It would be really nice to have this or some way to ignore certain attributes.

@VladimirMikulic
Copy link

@davenquinn @LukeTOBrien @Xeevis @karmanyaahm may be a bit late here, but I've made a plugin that excludes assets from bundling in Parcel 2.

Plugin: 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", "..."]
}
  1. package.json
{
  "parcelIgnore": [
    "_framework",
    "_content"
  ]
}

Now you are good to go!
Let me all know what you think!

@krutoo
Copy link

krutoo commented Aug 1, 2022

Any updates? Only solution provided by @VladimirMikulic worked for me with Parcel 2

pkgw added a commit to tectonic-typesetting/tectonopedia that referenced this issue Mar 1, 2023
We'd like our internal URLs to point to locations like `../end/`, not
`../end/index.html`. But with Parcel.js this is actually surprisingly
hard to get working, as documented here:

parcel-bundler/parcel#1186

By adding the `parcel-resolve-ignore` module we can get things working,
since we index all of our inputs in the magic `_all.html` file. It adds
some additional output that's a little annoying but it's worth it, I
think.
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