Sharing node_modules chunks across builds (webpack) - javascript

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.

Related

Building a Webpack 4 Config for SASS (Compilation, Minification in Prod), JS (Concat + Minification), and Multiple Vue Single Page Applications

Trying to setup a webpack setup for my entire resource generation workflow in our app. I don't need any hot reloading, browsersync, etc. Just needs to watch for changes, and rebuild depedent objects when changes are made. File structure looks like this:
(I apologize for the image I seriously looked up other methods to post structure, but nothing was working on the preview, I can post a fiddle-or-codepen with this output in a comment afterwards)
The only areas of note are:
1) Each folder underneath vue-spas each Single-Page Mini App (SPAs) generates it's own output file of the app.
2) All items in constructs underneath js are concat and minified into one output file (/dist/js/main.min.js) but every item underneath js/components/ just renders a minified and mangled version of that file
Lastly, I understand this is probably a difficult question to wrap around, but I have Gulp doing some of it now, and Webpack doing the Vue compilation, just trying to see if it's possible to consolidate into just webpack and let it do the work.
Thanks for any assistance.
There are a few approaches. The simplest would be to add a key for each app in the entry point configuration in your webpack.config.js file.
That would look like this in your webpack.config.js file:
module.exports = {
entry: {
app1: './vue-spa/vue-spa1/app.js',
app2: './vue-spa/vue-spa2/app.js'
// etc
}
};
This will output individual directories in your dist for each with a nicely bundled app file.
By default, if you pass in a production variable to your webpack build command it'll apply all the optimizations you're looking for. If it's lacking out-of-the-box, there's likely a loader that can handle whatever optimization you need.
For Sass, you can add sass-loader to your webpack file:
https://github.com/webpack-contrib/sass-loader
Your devServer can just watch your vue-spa directory recursively for changes.
Another approach is to use lerna -- though that would require additional configuration, and is only necessary in your situation if you're in an enterprise environment where each individual app is being shipped out to a private NPM registry, and require individual semver.

Packaging sub-modules with rollup for node

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.

How to bundle in Webpack assets in multiple pages that don't link to every other assets?

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.

Webpack - entry point common dependencies

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.

Using webpack to generate typescript libraries with typing files

Currently my process for building is:
Write lots of typescript files with ES6 module syntax
Generate an index.ts which re-exports all modules from one point
Compile to CommonJS + System
Output Descriptor/Typing files
This results in an index.js file which re-exports all the internal files without the developer consuming it needing to know about it, as well as a lot of d.ts files which mirror the file structure.
Now this works, but if I were to take this approach to the browser I would need to webpack up all the js or it would be a http request nightmare pulling in all the individual files. Currently this library would be consumed as a dependency for other libraries, so it is not an end point for logic or anything it is a module/library.
Now the main question is with webpack I know I can load TS in and get a commonJS module out, however I cannot find any way to generate d.ts files with webpack. So is there a way for me to use webpack as the compiler/packager in this scenario and have an output my-lib.js and my-lib.d.ts rather than the current approach which yields lots of individual files.
== Extra Clarification on Use Case ==
Just to try and make sure everyone is on the same page here when I say it is a library that would be re-used what I mean is that this is something that would be loaded via npm or jspm or something as a module dependency for other modules.
So for example let us pretend jquery doesn't exist and I am going to create it but write it in typescript for other developers to consume in both JS and TS. Now typescript outputs both js files and d.ts files, the js files are to be used as you would expect, but the d.ts files explain to other typescript files what the types contained within the library are.
So assuming I have developed jquery in TS as listed above, I would then want to publish this output (be it created by webpack or tsc) on npm/jspm/bower etc. So then others can re-use this library in their own projects.
So webpack typically is used to package an "application" if you will, which contains logic and business concerns and is consumed directly as an entry point to a larger set of concerns. In this example it would be used as a compilation and packaging step for a library and would be consumed via var myLib = require("my-lib"); or similar.
Generating the .d.ts files is not related to webpack. With webpack you can use either ts-loader or awesome-typescript-loader. Both of them make use of tsconfig.json. What you need to do is to add declaration: true in your tsconfig.json.
I'd also suggest you to take a look at typescript-library-starter. You'll find how's set up there, including UMD bundle and type definitions :).

Categories

Resources