parcel-bundler / parcel

The zero configuration build tool for the web. πŸ“¦πŸš€
https://parceljs.org
MIT License
43.5k stars 2.27k forks source link

Directory as entry point & Better management of (static) assets and directory structures #4548

Open filips123 opened 4 years ago

filips123 commented 4 years ago

πŸ™‹ feature request

This feature request covers a few different, but related, things. They are mostly related to handling static assets and directory structures. Related existing issues are #2056, #2099 and #2991, as well as some other issues that are liked by those issues.

πŸ€” Expected Behavior

Behaviour should be configurable with flags/argument, but once some specific flags would be enabled, this is how should Parcel handle things.

If a directory is provided as an entry point, Parcel should only treat specific files (for example, all HTML files, but this should be configurable by user) as "real" entry points which would normally resolve and bundle all files linked by them, just like it is done currently when a file is provided as an entry point. Update: I don't know if this is already the case, but all of those entry points should have separate bundles, but content/code that is shared between them should be split/extracted into some "common" file instead of duplicating it. Another Update: It should also be possible to exclude specific file that is linked from a bundle from processing and just copy and include it as-is.

Then, for handling directory structure of those bundled files, multiple things should be possible:

Additional new thing is handling of other (non-included and probably static) assets. Examples of such assets can be robots.txt, CNAME for GitHub Pages, various other configuration or data files that need to preserve content and directory structure... Those files should just be copied to dist folder (or maybe minified if this would be requested by user) while preserving content, type and directory structure.

😯 Current Behavior

Currently, the above features are not possible.

The only similar way of providing directory as entry point is *.html, but this leaves out all static assets. Adding JSON configuration files as entry points transforms them as JS files, which basically makes them useless.

Changing the directory structure is not possible easily.

πŸ’ Possible Solution

Because this is quite a lot of features and configurations, all of them probably shouldn't be implemented directly in Parcel's core. Instead, they should probably be implemented in (official) plugins. However, this would probably require changing some of the plugin APIs.

Configuration should be done in .parcelrc, package.json or similar config files (but should be consistent across all of the plugins).

For example, specifying which files should be treated as bundle entry points, based on .gitignore syntax ported to JSON:

{
  "entrypoint": [
    "*.html", // All HTML files
    "*.{js,ts}", // All JS and TS files
    "modules/*", // All files in modules directory
    "!something.html" // Excluding specific file
    "!other/*.{ts,js}" // Excluding more files
  ]
}

Then for specifying directory structure:

{
  "output": {
    // Flatten structure of JS (and other bundled files that are transformed to JS files) files, use filename hashes, put them into `js` directory of dist directory
    "*.js": {
      "flatten": true,
      "hash": "filename",
      "directory": "js"
    },

    // Flatten structure of CSS (and other bundled styles that are transformed to CSS) files, use content hashes, put them into `css` directory of dist directory
    "*.css": {
      "flatten": true,
      "hash": "content",
      "directory": "css"
    },

    // All other bundled files (HTML, images...) should preserve original directory structure, shouldn't be hashed and should be placed directly into dist directory (or its subdirectories, depending on original directory structure)
    "*": {
      "flatten": false,
      "hash": false,
      "directory": "."
    },

    // Multiple extensions at the same time
    "*.{some,other,extensions}": {
      "flatten": true,
      "hash": "content",
      "directory": "assets"
    },

    // Excluding specific filenames which should be handled by other output type, in this case `*` which matches all files
    "*.js": {
      "flatten": true,
      "hash": "filename",
      "directory": "js",
      "exclude": ["js/index.js", "excluded/*"]
    }
  }
}

Other (non-included and probably static) assets should just be copied without any changes, but there could be configuration to, for example, verify their structure, minify them..., which would be provided by additional plugins.

πŸ”¦ Context

Reason for supporting non-included static assets is that I want to have additional configuration files that are used by external applications (like robots.txt, CNAME and others). Or, for example, website can have pre-defined structure with some configuration or data files.

I know that I could just copy them before or after running Parcel, but then I would lose watching and auto-reloading features. I also can't just add JSON configuration files as entry points, because they will be transformed to JS.

Reason for managing directory structure is also similar. You may need pre-defined structure for external applications, want to do some custom directory-based configuration on server, or just for usability and aesthetic reasons (it is easier to find/copy/manage files if they are split into some directory structure and also looks cleaner).

I know that Parcel is mainly meant for bundling files, this would still be useful for the reasons I mentioned. And even if it is "zero configuration bundler," some configuration (maybe provided by plugins) would still be useful.

I also know that for more advanced configurations, Webpack or other "big" bundlers should be used. However, Webpack would require a lot of configuration, while Parcel, if implemented properly, would just require some configuration that actually is needed.

I mainly choose Parcel for my project because of a good plugin system that doesn't require configuration for every file type. However, expending this with some configuration for the above features would be a lot better than manually configuring everything in Webpack.

πŸ’» Examples

Are already in the above sections, but I can provide more if needed.

mischnic commented 4 years ago

Because this is quite a lot of features and configurations, all of them probably shouldn't be implemented directly in Parcel's core. Instead, they should probably be implemented in (official) plugins. However, this would probably require changing some of the plugin APIs.

As far as I can tell, everything you requested should be possible with a Namer plugin: https://github.com/parcel-bundler/parcel/blob/v2/packages/namers/default/src/DefaultNamer.js#L14 it takes a bundle and returns a path where it should be placed.

And even if it is "zero configuration bundler,"

The point here is "no configuration is needed", not "is not configurable" or opinionated.

"entrypoint": [

This is already possible with "source": [ in package.json, though globs don't work in that list: https://github.com/parcel-bundler/parcel/issues/3821

skipjack commented 1 year ago

@mischnic is there any documentation for this source approach you mentioned? Just searched in the docs but I'm not seeing anything...

image

I'm just looking for the simplest approach for telling parcel to copy over static assets and locales files with renaming them.

AndrewKvalheim commented 1 year ago

Docs β†’ Targets β†’ Entries β†’ package.json#source

https://parceljs.org/features/targets/#package.json%23source

Darrenbydesign commented 1 year ago

Because this is quite a lot of features and configurations, all of them probably shouldn't be implemented directly in Parcel's core. Instead, they should probably be implemented in (official) plugins. However, this would probably require changing some of the plugin APIs.

As far as I can tell, everything you requested should be possible with a Namer plugin: https://github.com/parcel-bundler/parcel/blob/v2/packages/namers/default/src/DefaultNamer.js#L14 it takes a bundle and returns a path where it should be placed.

And even if it is "zero configuration bundler,"

The point here is "no configuration is needed", not "is not configurable" or opinionated.

"entrypoint": [

This is already possible with "source": [ in package.json, though globs don't work in that list: #3821

Why don't globs work with the source list and when can we expect to do this?

Also, I'd be interested in using the Namer plugin to output assets to specific locations via globs as you suggested is possible. I don't think I'm smart enough to understand how to use the Namer plug-in though.

mischnic commented 1 year ago

Why don't globs work with the source list

I don't think there's a particular reason. Just that nobody has added it yet

Also, I'd be interested in using the Namer plugin to output assets to specific locations via globs as you suggested is possible. I don't think I'm smart enough to understand how to use the Namer plug-in though.

I don't know exactly what you're trying to do, but here are two existing plugins that some something like that:

Darrenbydesign commented 1 year ago

Why don't globs work with the source list

I don't think there's a particular reason. Just that nobody has added it yet

Also, I'd be interested in using the Namer plugin to output assets to specific locations via globs as you suggested is possible. I don't think I'm smart enough to understand how to use the Namer plug-in though.

I don't know exactly what you're trying to do, but here are two existing plugins that some something like that:

Thanks I took a look at those and I think they will get me what I need