How to bundle js library for use in browser with webpack? - javascript

I'm trying to create a minified version of a js library with webpack.
The library consists of one main function with prototypes that is exported and of several other functions it depends on that are imported in the file of the main function. This works without bundling and I assume that this file should the entry point for webpack.
I aim to bundle it into some mylib.min.js to be able access it in the browser like I would use jQuery or similar libraries. So I don't want to bundle the whole web app, just the JS library I wrote.
I'm not really getting along with it, since all tutorials show how to bundle the whole web app. My questions are:
how do I have to export the main function of the library to be able to access it in the browser?
how do I need to configure webpack?
how should I include and access the bundle in the browser?
If you could recommend any example (like tutorial, gitub repository that does this, ...) I would be happy! Any suggestions welcome!

Have you look at the documentation on the webpack website?
Here an example
For widespread use of the library, we would like it to be compatible in different environments, i.e. CommonJS, AMD, Node.js and as a global variable. To make your library available for consumption, add the library property inside output:
webpack.config.js
var path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
- filename: 'webpack-numbers.js'
+ filename: 'webpack-numbers.js',
+ library: 'webpackNumbers'
},
externals: {
lodash: {
commonjs: 'lodash',
commonjs2: 'lodash',
amd: 'lodash',
root: '_'
}
}
};
If you have any other question about that specific documentation just google webpack js authoring libraries. you'll be redirect to the good website. Website are subject to change pattern.

Related

Webpack tree shaking not working between packages

Good evening!
I have been trying for a few days to get tree shaking between different packages to work.
Before going further, I have created a minimum repro that I will explain throughout this post: https://github.com/Apidcloud/tree-shaking-webpack
I have also opened an issue on webpack repo: https://github.com/webpack/webpack/issues/8951
For simplicity sake, the example just uses webpack. Babel is not used.
The above example has two packages, both with their respective bundle:
core - exports 2 functions, cube and unusedFn
consumer - imports cube from core and exports its own function, consumerFn
Core package
Note that square function is not exported in the index.js file. It's a way to know that tree shaking is indeed working within core at least, as it's not included in the final bundle (which is correct).
Consumer package
As you can see, only cube is being imported from core. It then exports its own function (consumerFn) consuming cube.
Problem
The problem is that the consumer bundle is including everything from the core bundle. That is, it's including unusedFn when it shouldn't, resulting in a bigger bundle.
Ultimately, the goal is to do the same in a monorepo with multiple packages. There's no point on having them if each package is bundling the everything from the others. The goal is to bundle only what's necessary for each package.
Using optimizationBailout I can see that ModuleConcatenation plugin is issuing some warning messages. I also used --verbose flag:
Here's my webpack.config.js:
const path = require('path');
module.exports = {
mode: 'production',
entry: {
core: './src/index.js',
consumer: './consumer/index.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
// for simplicity sake I removed the UMD specifics here.
// the problem is the same, with or without it.
},
optimization: {
usedExports: true,
sideEffects: true
},
stats: {
// Examine all modules
maxModules: Infinity,
// Display bailout reasons
optimizationBailout: true
}
};
I also have "sideEffects": false in the package.json.
I went through webpack's guide too, but I'm not sure what is missing.
Related issues:
webpack-3-babel-and-tree-shaking-not-working
webpack-including-unused-exports-in-final-bundle-not-tree-shaking

webpack & using node modules in an isomorphic package

I am building an isomorphic package where I am using a flag in various files to detect if we are in the browser or in node. If in node, I require an internal package ie if (isNode) { require("/.nodeStuff) } that has as one of its dependencies the fs module. However, webpack does not like this for obvious reasons. Is there any type of module-based webpack config file that I can configure to ignore the node-based requires entirely so that this does not happen?
First option
As stated in the docs, in order to solve this isomorphic problem you could simply run two builds, one for each environment (node and web). The guide can be found here. Keep in mind you should probably mock any built ins in the clientConfig by adding this block
node: { fs: 'empty',//any other node lib used }. That way webpack will not complain and since your client code will be under the !IS_NODE condition the empty fs will never be used.
Although this is a solid solution you end up with 2 bundles and you need of course a way to distribute them to the correct platform each time.
Second way
This solution is based on the not very well known __non_webpack_require__ function. This is a webpack specific function that will instruct the parser to avoid bundling this module that is being requested and assume that a global require function is available. This is exactly what happens while running in node instead of a browser.
//webpack.config.js
{
mode: "development",
entry: './index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
node: false
}
// nodeStuff.js
const fs = __non_webpack_require__('fs'); //this will be transformed to require('fs')
fs.writeFileSync('some','thing)
That way since nodeStuff.js will only be required under the IS_NODE condition, the native require will be available.
I would suggest to use __non_webpack_require__ on native libraries only, that you are sure that will be available!

How to publish a library of Vue.js components?

I am working on a project containing a Vuex module and an abstract components that users can extend from.
I would love to publish this on NPM to clean up my codebase and pull this away from my project as a solid well tested module. I have specified the main file in package.json to load an index which imports everything I want to expose:
https://github.com/stephan-v/vue-search-filters/
The index contains this at the moment:
import AbstractFilter from './src/components/filters/abstract/AbstractFilter.vue';
import Search from './src/store/modules/search';
module.exports = {
AbstractFilter,
Search
};
For this to work I need to transpile this since a babel compiler normally won't transpile files imported from node_modules(Correct me if I am wrong here). Besides that I would probably be a good idea to do this so it can be used by different systems.
How do I transpile only the files that I need though with Webpack? Do I have to create a separate config for this?
What does a config like that look like? I know the vue-cli has a build command for one single file component but this is a bit different.
Any tips or suggestions on how to transpile something like this are welcome.
Edit
This seems like a good start as well:
https://github.com/Akryum/vue-share-components
The most import thing for Webpack users to notice is that you need to transpile your files in UMD which can be set by:
libraryTarget: 'umd'
This will make sure your are transpiling for Universal Module Definition, meaning your code will work in different environments like AMD,CommonJS, as a simple script tag, etc.
Besides that it is import to provide the externals property in webpack:
externals: {}
Here you can define which libraries your project users but should not be built into your dist file. For example you don't want the Vue library to be compiled / transpiled into the source of your NPM package.
I will research a bit more, so far the best options looks like to create a custom project myself If I want flexibility and unit testing.
Webpack docs
This is also a useful page which goes in depth about how to publish something with Webpack:
https://webpack.js.org/guides/author-libraries/#add-librarytarget
The best way probably will be to build the module and set main in your package.json to my_dist/my_index.js. Otherwise every project that will use your module will have to add it to include which is tedious.
You will also want your webpack build to follow UMD (Universal Module Definition). For that you must set libraryTarget to umd:
...
output: {
filename: 'index.js',
library:'my_lib_name',
libraryTarget: 'umd'
},
...
Also a good thing will be to add Vue to externals so that you didn't pack extra 200kb of vue library.
externals: {
vue: 'vue'
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
And add it to peerDependencies in package.json:
...
"peerDependencies": {
"vue": "^2.0.0"
},
"devDependencies": {
"vue": "^2.0.0"
}
...
If you need an existing example of how to pack a vue.js component, you can take a look in one of the modules I maintain:
https://github.com/euvl/vue-js-popover
Particularly webpack.config.js and package.json will be interesting for you.
I was searching for a similar solution and found rollup https://github.com/thgh/rollup-plugin-vue2 (but was not able to make it work) and this component https://github.com/leftstick/vue-expand-ball where all the component code gets compiled to one reusable js-file.
I know that's not a proper solution but maybe it's sufficient for your needs.

Webpack: Using multiple build targets

Given an (Angular-)Webapp with a Webpack-buildprocess I would like to add several build-targets to my Webpack configuration.
There are plenty tutorials on how to modify your webpack.config at compile time, which is already helpful (and probably all I need) to get dev and prod builds running.
However I was hoping that there is a way to parametrize the build process so that different files are used for the build-process.
Question
How do i configure Webpack to replace all *.js/ *.html-Files with files called *.mobile.js/ *.mobile.html (if available) during the build-step?
Bonusquestion:
How do I exclude environment-specific import statements via webpack-config?
Example
I got several view/controller-pairs which are linked via Angulars $stateprovider. In the mobile version of the webapp most of the HTML-views should be a mobile-optimized template.
If I use several entry-points for webpack to generate a desktop-version and a mobile-version I would have to rewrite every file where HTML-Files are required or imported for each of my build-targets and specify the new filenames manually.
This would cause a lot of code-duplication and is hard to maintain.
I ended up using the following in my webpack.config
const target = env && env.mobile ? 'mobile' : 'desktop'
resolve: {
extensions: [`.${target}.js`, '.js', `.${target}.html`, '.html']
}

Is it possible to write Chrome Apps using node.js modules?

I want to write a Chrome App, but I also want to inter-op with some .Net code using Edge.js. Now I've tried it out in a Nodejs app, but am unable to figure out how to do it in a Chrome App.
I've watched the YouTube video of Paul Kinlan (the Chrome Apps office hours - NodeJS in chrome packaged apps), but can't get the code to run. I've also tried browserify with no success.
Is there a working sample which uses any of the node modules in a Chrome App (because the available resources look to be older).
Thanks in advance,
Manoj.
I've run code written for node.js inside a chrome packaged apps, and have used modules published to npm, using either browserify or webpack.
The only real tricky bit for me traditionally has been exporting functionality for use by my web app, since you don't have access to require(). I usually just create a special module that exports all global symbols I want to access and use that as my entry point.
E.g., using webpack, I'd create a file called globals.js:
module.exports = exports = {
a: require('a'),
b: require('b'),
...
}
Then create a webpack.config.js:
module.exports = {
context: __dirname + "/js",
entry: {
globals: [
"globals.js",
],
},
output: {
// Make sure to use [name] or [id] in output.filename
// when using multiple entry points
path: __dirname + "/js/generated",
filename: "[name].bundle.js",
chunkFilename: "[id].bundle.js",
library: "[name]",
libraryTarget: "umd",
}
};
Then I can pack that and include the generated bundle in my application, and use the global variable globals now.
I am not sure Edge.js works, but I would not consider it likely that it will be possible to webpack/browserify that into a web/chrome app, because their is no support for native bindings, and inter-process communication is a lot different. I'm just not sure how it could work.
(But you can probably implement your own interop with .net applications using a different kind of IPC, perhaps)

Categories