florianrappl / parcel-plugin-externals Goto Github PK
View Code? Open in Web Editor NEWParcel plugin for declaring externals. These externals will not be bundled. :package:
Home Page: https://piral.io
License: MIT License
Parcel plugin for declaring externals. These externals will not be bundled. :package:
Home Page: https://piral.io
License: MIT License
As I use in my own plugin, there is a package @parcel/logger
that integrates directly with Parcel's logging system. I would suggest using it instead of console
because it looks much cleaner (you can install that plugin to see for yourself). You could also throw errors for prettier output than console.error
.
I have a declaration file for @parcel/logger
, which should give you a general sense of its API.
The package.json browser field allows properties to be set to false to exclude files from bundling. However, this causes parcel-plugin-externals to crash as resolve does not accept values other than strings.
Continuing from parcel-bundler/parcel#144 (comment)
Maybe I'm not doing it just right or not understanding how things work, but here's what I've got so far:
The issue here is that WordPress is already loading React and ReactDOM via the @wordpress/element
package from yoursite-com/wp-includes/js/dist/element.js
(WordPress core, not my own path, as you can see).
Here's my package.json
:
{
...
"dependencies": {
"react-notifications-component": "^2.3.0"
},
"devDependencies": {
"@babel/core": "^7.8.7",
"@wordpress/scripts": "^7.1.2",
"npm-run-all": "^4.1.5",
"parcel-bundler": "^1.12.4",
"parcel-plugin-externals": "^0.3.3",
"postcss-modules": "^1.5.0"
},
"babel": {
"presets": [
"@wordpress/default"
]
},
"browserslist": [
"extends @wordpress/browserslist-config"
],
"externals": "./.externals.js"
}
Here's the .externals.js
that my package.json
runs:
const rxWp = /node_modules\/@wordpress\/(.*?)\//;
const rxBabel = /node_modules\/@babel\/(.*?)\//;
const rxReact = /node_modules\/react-(.*?)\//;
module.exports = function( path ) {
const wp = rxWp.exec( path );
const babel = rxBabel.exec( path );
const react = rxReact.exec( path );
let wpSuffix;
let babelSuffix;
let reactSuffix;
let reactName;
if ( wp ) {
wpSuffix = wp[ 1 ];
return `@wordpress/${wpSuffix} => require('@wordpress/${wpSuffix}')`;
}
if ( react ) {
reactSuffix = react[ 1 ];
reactName = reactSuffix[ 0 ].toUpperCase() + reactSuffix.substr( 1 );
return `react-${reactSuffix} => React${reactName}`;
}
if ( babel ) {
babelSuffix = babel[ 1 ];
return `@babel/${babelSuffix} => require('@babel/${babelSuffix}')`;
}
return undefined;
};
Just a quick thought, since I'm using the externals
key in parcel-plugin-html-externals
as well, that might introduce conflicts in case someone wanted to use both packages. Would you be interested in merging or introducing HTML support here?
When adding [email protected] to externals bundling is failing due to the specified module doesn't exist.
ร ENOENT: no such file or directory, lstat 'C:\Users<...>\node_modules\react-dom\unstable-fizz.browser.js'
at realpathSync (fs.js:1476:7)
at externals.push.modules.map (C:\Users<...>\node_modules\parcel-plugin-externals\utils.js:165:15)
at Array.map ()
at makeResolver (C:\Users<...>\node_modules\parcel-plugin-externals\utils.js:163:18)
at combineExternalsPrimitive (C:\Users<...>\node_modules\parcel-plugin-externals\utils.js:201:12)
at combineExternals (C:\Users<...>\node_modules\parcel-plugin-externals\utils.js:210:18)
at retrieveExternals (C:\Users<...>\node_modules\parcel-plugin-externals\utils.js:257:14)
at module.exports (C:\Users<...>\node_modules\parcel-plugin-externals\index.js:9:21)
at Bundler.loadPlugins (C:\Users<...>\node_modules\parcel\src\Bundler.js:219:17)
In package.json of react-dom:
"browser": {
"./server.js": "./server.browser.js",
"./unstable-fizz.js": "./unstable-fizz.browser.js"
},
In such cases i.e. when referenced module doesn't exist makeResolver function breaks.
Any reason the externals value has custom syntax with '=>' instead of an object? Would prefer something like this
{
"externals": {
"react": "React"
}
}
over
{
"externals": [
"react => React"
]
}
Hi!
I am happy user of your plugin. However I am trying to move a site using it to a package inside a monorepo that uses lerna
+ yarn workspaces
.
With this setup all the dependencies are hoisted. This means the paths passded by parcel will be different from the ones calculated by this plugin and the external modules will not be externalized.
I've created a sample repo where you can see the issue in action: https://github.com/4lejandrito/parcel-plugin-externals-yarn-workspaces-issue-demo.
Run yarn && yarn start
on it and you'll get a page that should have a dependency externalized (and therefore fail) but it will actually exist in the bundle and print a message on the screen.
I am currently working with webpack
and considering looking into adoption of parcel
for a variety of reasons. So far, externals seems to be the primary feature that is missing when considering this adoption. We need to leverage externals in two different ways. I wanted to know if this plugin currently supports our two use cases and, if not, whether it would be possible to add this support.
First use case: typical webpack
externals. This is the normal use case and the one I am fairly certain is supported. In a situation where I am developing a single page application and I know that jQuery
will be available globally I can list it as an external and not include it in the application's bundle.
Second use case: marking all node_modules
as externals. This is the use case I am not as confident is supported. We develop a number of internal libraries and we know for a fact that the dependencies of those libraries will be downloaded by the applications that consume those libraries. Therefore, whenever we bundle a library, we list all of its dependencies as externals using a library designed for webpack - webpack-node-externals
. Is it possible to mimic this behavior using this plugin?
I'm seeing this error in version 0.4.1 and node 8.16.x:
Plugin parcel-plugin-externals failed to initialize: /foo/node_modules/parcel-plugin-externals/utils.js:137
} catch {
^
SyntaxError: Unexpected token {
at NativeCompileCache._moduleCompile (/foo/node_modules/v8-compile-cache/v8-compile-cache.js:242:18)
at Module._compile (/foo/node_modules/v8-compile-cache/v8-compile-cache.js:186:36)
...
Looks like that should be catch () {...
. Works in Node 10.16.x.
Is this plugin compatible with Parcel v2 beta?
I tried every combination of:
{
"peerDependencies": {
"jquery": "*",
"jquery.js": "*",
"bootstrap": "*"
},
"externals": [
"jquery => jQuery",
"jQuery => jquery",
"jquery => require('jquery')",
"jQuery => require('jquery')",
"jQuery => require('node_modules/jquery/dist/jquery.js')",
"jquery => require('node_modules/jquery/dist/jquery.js')",
"$ => require('node_modules/jquery/dist/jquery.js')"
],
}
Importing like that:
import $ from 'jquery';
But jQuery is bundled into my app.js
whatsoever :-(
2 questions for a situation where my app loads within WordPress and therefore globals like jQuery, Moment, Lodash, React, and ReactDOM are already...
References:
"*"
actually do?lodash.isequal
get excluded from my own build?Any and all suggestions for my "externals" are welcome! :D
===
Here's a Parcel build report:
Here's an example npm ls ...
:
Here's my externals:
{
...
"externals": {
"@babel/runtime/regenerator": "regeneratorRuntime",
"@wordpress/element": "wp.element",
"jquery": "jQuery",
"lodash": "lodash",
"lodash-es": "lodash",
"moment": "*",
"react": "React",
"react-dom": "ReactDOM"
}
...
}
"dependencies": {
"aws-sdk": "2.585.0"
},
"externals": {
"aws-sdk": "aws-sdk"
},
"devDependencies": {
"@types/aws-lambda": "^8.10.47",
"@types/node": "^13.9.8",
"parcel-bundler": "^1.12.4",
"parcel-plugin-externals": "^0.3.3-pre.20200323.2",
"typescript": "^3.8.3"
},
"engines": {
"node": ">=12.0.0 <13.0.0"
}
Code written in Typescript.
Generally bundle all node_modules
except a few external ones ("aws-sdk" for a lambda in my case).
My index.ts
looks something like this:
import { Handler } from 'aws-lambda'; // Types only "@types/aws-lambda" in devDependencies
import { Athena } from 'aws-sdk';
import { format } from 'util';
// Other code imports local to src folder [...]
export const handler: Handler = async (event, context) => {
const athenaService = new Athena();
//...
return format('%s Done', 'Really');
};
When I compile this normally with e.g.
parcel build ./src/index.ts --out-dir dist --out-file index.js --global handler --target=node --experimental-scope-hoisting --no-source-maps --no-content-hash
it works correctly and the require('aws-sdk')
is correctly left in the output.
But if I compile it with the --bundle-node-modules
it breaks and the output contains something like this:
var k={};k=aws-sdk;
also the parcel output shows:
dist/index.js 1.33 KB 1.38s
dist/aws-sdk => aws-sdk.5848e953.external 0 B 26ms
In both cases the require('util')
is present in the output as it should.
When I run the script:
" parcel build src/index.html "
to build on production, the externals ones are not bundled. Good.
"parcel src/index.html"
to develop, the external ones are NOT bundled but I need them in dev mode. ๐ฅ
How can I prevent this behavior? I need those modules to develop
I tried to do
NODE_ENV=production
NODE_ENV=development
the externals modules are included in package.json
into "externals"
array.
Let me know if you need any more details
Thanks
I am using Parcel 1.12.4 which is installed globally.
I installed this plugin globally
npm install -g parcel-plugin-externals
I ran into this error message:
'Error: Cannot find module 'parcel-bundler/src/Logger'
But I think I resolved it by adding some missing files as per
https://stackoverflow.com/questions/62870976/parcel-plugin-transcrypt-fails-with-error-cannot-find-module-parcel-bundler-s
I added the following to my package.json but I am not confident that I did it correctly.
"externals": [
"userConfig"
],
"alias": {
"userConfig": "../config/user_config.js"
}
When I run my parcel build I can not see if the plugin is working, but my desired end result is definitely not working.
I think I have an incredibly simple use case. I have an external file that I want to import manually and I want Parcel to ignore it. I want my import statement to remain exactly as it is:
At run time if I perform
import('../config/user_config.js')
I want it to read that actual file on in that location and not be redirected to some bundled code.
Am I asking too much?
I am writing a VSCode extension that imports the vscode
module for interfaces and other things. However, this module does not exist and is provided on the fly by the editor, so there is an error when trying to build the extension. Does this plugin support scenarios like this?
Here is the project: https://github.com/arnohovhannisyan/vscode-syncify.
I tried adding the vscode
module to both externals
and peerDependencies
but it didn't work.
I'm able to exclude react from the build using "parcel-plugin-externals".
However, when I dynamically load the compiled script file into another project that already is using react, I get the error message "Uncaught ReferenceError: React is not defined". How do I make the script load the excluded module from the script it is being loaded into?
( If that make sense to you, I realize this is a very incomplete description )
More details on what I'm trying to do:
We are building a SPA application for a CMS using react, parcel and typescript.
We want to build a plugin system that will allow third party developers to create their own controls that plug into the CMS UI. These ui components must be loaded dynamically and from external sources.
We distribute our CMS components to NPMJS and third party developers will develop their plugins by referencing the NPM modules. The output of these projects should only contain the custom code they have written. I'm trying to use Parcel with "parcel-plugin-externals" to build a script file that can be loaded dynamically into the CMS at runtime.
To load the script file with:
const loadedScrips: Set<string> = new Set();
async function loadScript(url: string): Promise<void> {
if (loadedScrips.has(url)) return;
loadedScrips.add(url);
return new Promise((resolve, reject) => {
var script = document.createElement('script');
script.onload = () => resolve();
script.onerror = (err) => reject(err);
script.src = url;
document.head.appendChild(script);
});
}
In the package,json we have added:
"externals": {
"react": "React"
},
Without the "externals" it works, with the "externals" section it fails with:
"Uncaught ReferenceError: React is not defined"
If you want, I could make a simplified example and upload it to github.
Any help with the matter is greatly appreciated !
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.