I'm using Webpack and building a library which will have multiple entry points, for example:
src/module1/module1.js -> dist/module1.js
src/module2/module2.js -> dist/module2.js
src/module3/module3.js -> dist/module3.js
src/module4/module4.js -> dist/module4.js
src/module5/module5.js -> dist/module5.js
However, each one of these modules may load one or more of the other modules as a dependency. How can I build each of these modules as an entry point without including other modules in the resulting dist files? For example, if module1 loads module2 and module3 as dependencies, I don't want the code for module2 and module3 to be included in dist/module1.js, but instead just remain as an import statement, taking into account the change in path (e.g. import '../module2/module2' becomes require('./module2')).
Is this something that's possible with Webpack? CommonsChunkPlugin seems to almost do what I want, but that'd require any consuming project to import both a common file and each module, which I'd want to avoid.
Related
I want to setup a webpack.config file that is able to dynamically accept entry points, and build them, whilst outputting all of the used node modules as chunks. So for example if we had:
// main-a.js
import { a, b, c } from 'node-module-a'
import hello from 'node-module-b'
I'd like to have an output folder that contains:
main-a.js
node-module-a.js
node-module-b.js
Note that node-module-a.js should contain all of its dependencies as well, so that node-module-a contains the entire imported library. So then if I used the same webpack configuration file with another entrypoint as shown:
// main-b.js
import { b, d } from 'node-module-a'
import there from 'node-module-c'
My output folder would now contain:
main-a.js
main-b.js
node-module-a.js
node-module-b.js
node-module-c.js
Loading both main-a.js and main-b.js from the browser should work.
What I tried
I tried achieving this with the optimisation.splitChunks option, to detect the node_modules and to place them into their own chunks. This seems to have a few issues:
It doesn't reliably seem to work with async modules (but that could just be a misconfiguration)
On production builds, the modules from the first build are not recognised by the second build
Is there a better way to achieve this? I get the hint that this isn't what splitChunks is designed for. The purpose here is to be able to use the node_modules that I've installed almost like modules, since I will have lots of different entry points, and don't want to include any of the node modules code in those entry points.
I have a library (ES6) which is composed on many sub-modules, say
- package.json
- lib
- my_package
- file1.js
- file2.js
- sub_module1
- file3.js
- file4.js
I currently do imports like this (all inside my package - using file resolution to find, not node_modules resolution):
import {func1} from 'lib/my_package/file1'
import {func3} 'lib/my_package/sub_module1/file3'
So, in practice I have many files across sub-directories.
I am now trying to package and publish my library, which will be installed under node_modules.
It seems to me that the node resolution algorithm (when behind node_modules) only allows for a single entry point (and there is nothing rollup can do about that)
I would like to be able to include many sub directories and files and for them to be resolved individually.
As far as I understand I have to include a single toplevel file that has all the export from machinery. I can only import that single top level file.
This means having to manually create that file. It also means losing the all the sub-module name structuring that comes from the directory structure.
I was wondering: is there any way one can import any other file from a node_module directly?
Node's resolution algorithm only resolves the first part of a module source, so if someone does this...
var foo = require('your-library/subdir/foo.js');
...then Node (or Browserify/Webpack/rollup-plugin-node-resolve) will correctly resolve that to
/path/to/project/node_modules/your-library/subdir/foo.js
The tricky part is that you want to author JavaScript modules, but if someone is using your library in Node then they need CommonJS modules. Rollup can't help you here — you would need to do a one-to-one ESM->CJS conversion for each module. So that means either using Babel, or authoring CommonJS modules in the first place.
I'm working on an application that needs to pull in the ReadiumJS library, which uses AMD modules. The app itself is written in es6 w/ webpack and babel. I've gotten the vendor bundle working correctly, and it's pulling in the built Readium file, but when I try to require any of the modules Webpack says it can't resolve them. Anyone ever do this before with Webpack and RequireJS? Here's some info that may help - not sure what else to include as this is my first time really using Webpack..
Folder Structure
/readium-src
/readium-js
/ *** all readium-specific files and build output (have to pull down repo and build locally)
/node_modules
/src
/app.js -> main entry for my app
/webpack.config.babel.js
webpack.config.js entries
entry: {
vendorJs: [
'jquery',
'angular',
'../readium-src/readium-js/build-output/_single-bundle/readium-js_all.js',
'bootstrap/js/alert.js' //bootstrap js example
],
appJs: './app.js'
}
Trying to require it in app.js
var readiumSharedGlobals = require('readium_shared_js/globals');
I never really got into using RequireJS, so really struggling to understand how to consume that type of module along side other types of modules with webpack. Any help greatly appreciated :)
Update
If I change my app.js to use this instead:
window.rqReadium = require('../readium-src/readium-js/build-output/_single-bundle/readium-js_all.js');
Then it appears to try to load all the modules, but I get a strange error:
Uncaught Error: No IPv6
At this point, I'm unsure of
Should I have to require the entire path like that?
Is this error something from webpack, requirejs, or Readium? Tried debugging, but couldn't find anything useful...
UPDATE 8/12/2016
I think this is related to an issue with a library that Readium is depending on: https://github.com/medialize/URI.js/issues/118
However, I'm still not clear on how to correctly import AMD modules with webpack. Here's what I mean:
Let's say I have an amd module defined in moneyService.amd.js like this:
define('myMoneyService', ['jquery'], function($) {
//contrived simple example...
return function getDollaz() { console.log('$$$'); }
});
Then, in a sibling file, app.js, I want to pull in that file.
//this works
var getDollaz = require('./moneyService.amd.js');
//this works
require(['./moneyService.amd.js'], function(getDollaz) { getDollaz(); }
//this does not
require(['myMoneyService' /*require by its ID vs file name*/], function(getDollaz) {
getDollaz();
}
So, if we cannot require named modules, how would we work with a third party lib's dist file that has all the modules bundled into a single file?
Ok, so there's a repo out there for an Electron ePub reader using Readium, and it's using webpack: https://github.com/clebeaupin/readium-electron This shows a great way to handle pulling in RequireJS modules with webpack.
One super awesome thing I found is that you can specify output.library and output.libraryTarget and webpack will transpose from one module format to another... freaking awesome! So, I can import the requirejs module, set output library and libraryTarget to 'readium-js' and 'commonjs2' respectively, then inside my application code I can do import Readium from 'readium-js';
There is something I couldn't understand about Webpack.
Most of the webpack examples show a main entry point app.js which imports all other react components for Webpack to recursively build a resultant file. If there were multiple entry points, like pageA.js and pageB.js, we put them into an array in the entry argument.
My problem however is that my "main" entry point doesn't use and import every single components. Maybe just some. On PageA, I might only import ComponentA and ComponentB. On PageB, I might only import ComponentB and ComponentC. Then in the main.js on my MainPage, I might only import ComponentD.
I can put main.js, PageA and PageB all into my entry points. But does that mean I have to add to the entry list in webpack config every time I have a new page?
How should I approach this scenario using Webpack?
Sounds like your setup is a typical webpack multi-page app, which is usually consist of common/vendor bundle (entry point), and separate bundles (entry points) for each page, like your PageA and PageB.
For each page you will need to include the common/vendor bundle first, and then include the page specific bundle.
<script src="common.js">
<script src="PageA.js">
Have a look at multiple-entry-points and multiple-commons-chunks. Webpack can automatically extract the common deps and bundle them together (1st example), or you can specify which deps should go into which common chucks (2nd example). Also have a look at common-chunk-and-vendor-chunk, which perfectly explained how common chuck works.
According to your description, your setup is very similar to the first example (multiple-entry-points).
And yes, you will probably need to add a new entry when you have a new page, like PageC.
Webpack's config is actually a JS module. This means that the object you return can be built programmatically rather than manually.
What you want is for webpack to handle chunks optimization properly for you. This, along with programmatically determining the pages you have, should allow you to generate all your assets.
I am building a bundle using the SystemJS builder that I'd like to include in another project. The problem I'm running into is that bundle A and bundle B might both contain a 'main' module, and when I bundle them and include them in another project, they collide and everything breaks.
Does SystemJS builder have a better way of namespacing? Or from preventing bundled modules from being exported at all? Or is there another tool I should be using?
SystemJS does not have an easy way to do what you want.
You could import the module by path instead of by name.
import x1 from "folder1/x.js"
import x2 from "folder2/x.js"
You could also try to have two instances of SystemJS.
https://stackoverflow.com/a/30954312/6101582
https://github.com/systemjs/systemjs/issues/982
You could also rename the modules.