How to properly shim jquery / Backbone using browerify-shim - javascript

I'm trying to build a standalone JS lib that uses backbone/jquery. Here's a sample repo that represents the lib I'm trying to build.
I have a few goals for this lib:
Don't expose ANY globals (ie wrap everything properly so nothing leaks)
Don't be affected by any other package tools like requireJS
This lib could be loaded into any other website and I don't want any conflicts with JS that might be there (which is beyond my control) such as requireJS
So, my understanding is that I can use browserify-shim to properly shim these modules such that they can be used as expected with require in browserify. I'm pretty sure the shim is supposed to undef defines and require when it wraps these modules, which would achieve goal #2. Goal #1 would hopefully then be achieved just by using browserify as expected.
I can't really seem to get this to work and I"m not sure if it's just my misunderstanding of browserify-shim. I seem to have the same problem whether or not I run browserify from the command line: browserify src/main.js -o build/main.js or using the gulp build.
Basically, it's as if browserify-shim isn't even running. If you open up the index.html, you can see that the requirejs code I've loaded in is definitely affecting my lib as Backbone is just an empty object, then requirejs crashes.
You can see my package.json here in the repo, and it looks roughly like this:
{
...
"browserify-shim": {
"./node_modules/jquery/dist/jquery.js": "$",
"./node_modules/underscore.js": "_",
"./node_modules/backbone.js": {
"exports": "Backbone",
"depends": [
"./node_modules/underscore.js",
"./node_modules/jquery/dist/jquery.js"
]
}
},
"devDependencies": {
"browserify": "^4.1.11",
"browserify-shim": "^3.6.0",
"gulp": "^3.8.1",
"vinyl-source-stream": "^0.1.1"
},
"dependencies": {
"backbone": "^1.1.2",
"jquery": "^1.11.0",
"underscore": "^1.6.0"
}
}
Not sure what I'm missing here, but I'm having no luck. I was wondering if anyone can help or at least corroborate that what I'm trying to achieve is correct and possible with browserify-shim.
Thanks.
edit
To illustrate that it's definitely not shimming the modules, I've created a build/main.js and a build/main-shimmed.js that are exactly the same. The main.js I ran with no shim config and the shimmed one had the above config. I'm clearly missing something here.

Browserify and Browserify-shim are working in this case, and your main.js is calling the right require.
The problem you are running into is the that libraries you are bundling are also attempting to wire up the AMD style configuration. Your "crossing the streams", beware of Gozer.
Either get versions without the AMD configuration loaders, or comment them out.

Related

Do I need both tsconfig type and angular script for Javascript libraries in an Angular project?

So I am wondering what is the correct way to load a Javascript library into an angular project. I am currently adding both the dependency and types dependency to the package.json:
"#types/jquery": "^3.3.38",
"jquery": "^3.5.1",
Then in the tsconfig.json adding the types:
"types": [
"jquery"
]
Then importing the script into the angular.json:
"scripts": [
"node_modules/jquery/dist/jquery.js"
]
Are all these steps needed and/or am I missing a step? I expected the typeRoots tag in the tsconfig to automatically find the types and load the scripts. I have also seen javascript libraries not able to find functions from other libraries so is there an additional step to initialize them?
You have nothing else to do.
The only thing you may miss is that when you use it in Angular you have to import it from the library with:
import * as $ from 'jquery';
One thing to improve is to change the inclusion of the script with the minified version:
"scripts": ["../node_modules/jquery/dist/jquery.min.js"]

Calling VueLoaderPlugin() causes 'findIndex' undefined error

I'm trying to integrate a Vue CLI app in another web project we are working with. The Vue app itself works when running the dev server bundled with Vue CLI.
The Vue application contains .vue files, so a loader for webpack is needed. I used the setup from the vue-loader documentation. When I ran webpack (via Grunt) I now get the following error:
Warning: Cannot read property 'findIndex' of undefined Use --force to continue.
After a lot of tinkering I figured out that the new VueLoaderPlugin(); line from the documentation mentioned above was the cause of this. However I do need this plugin to get my .vue-files to work.
I am using the following set of loaders, imported using npm via package.json:
{
// ...
"dependencies": {
//...
"webpack": "~3.9.1"
},
"devDependencies": {
// ...
"vue": "^2.5.17",
"vue-html-loader": "^1.2.4",
"vue-loader": "^15.4.2",
"vue-template-compiler": "^2.5.17"
}
}
I have tried googling for the error but came up empty handed. All help and suggestions are welcome. Cheers!
When fiddling around trying to get the vue-loader to work, at some point I got an error leading me to update webpack to a later version. This version seemed to have deprecated the use of module.loaders in favour of module.rules.
Changing this in the webpack config seems to have made everything work smoothly. Hope someone finds this useful!

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.

How to compile all dependencies with browserify?

I am trying to learn how to use browserify so I can compile all my dependencies to one file. All the dependencies are being pulled in with NPM through updating a package.json. For example, I want to create a file with browserify that consists of the compiled javascript from this json file.
"dependencies": {
"highcharts": "0.0.11",
"bootstrap": "3.1.0"
}
I would like to do this on the fly and have it automatically pull from this json file.
You need to require the dependencies in whatever module you need them. For example, if one of your dependencies is Lodash, you'll require it where you use it:
var lodash = require('lodash');
module.exports = function() {
// do something with lodash in here if you want
};
The purpose of using something like browserify, webpack, etc., is that you specifically don't compile everything into a "global dependency bundle", as this subverts the modularization that those libraries (browserify, webpack) are meant to impose.

Set custom paths to files in Browserify

I'm taking a crack at changing my current RequireJS workflow to a Browserify + Watchify one, solely for my frontend Javascript (my backend is Ruby). The only issue I'm running into is that I don't have an easy place to configure what I would called "named paths". Let's assume my frontend is structured like so:
app/
models/
ExampleModel.js
views/
ExampleView.js
main.js
util/
backbone-all.js
vendor/
jquery-2.1.0.js
backbone-1.1.2.js
backbone-marionette-2.0.1.js
underscore-1.6.0.js
In the example above, please note two things:
All of my vendored JS files have their version right in their filename
Note the backbone-all.js file in the util folder
With RequirejS, I could do something like the following:
require.config({
paths: {
"jquery": "vendor/jquery-2.1.0",
"backbone": "vendor/backbone-1.1.2",
"underscore": "vendor/underscore-1.6.0",
"backbone-all": "util/backbone-all"
}
});
And be able to require my code simply by name, rather than fully qualified (or even relative) path. I haven't yet been able to figure out a way to get this to work the exact way that I want on the frontend. The closest I got was to create a dependency map file that is loaded before my application starts (and is globally available), and use it as the keys:
window.d = window.dependency = {
"jquery": "/vendor/jquery-2.1.0",
"backbone": "/vendor/backbone-1.1.2",
"underscore": "/vendor/underscore-1.6.0",
"backbone-all": "/util/backbone-all"
};
var $ = require(d.jquery);
Has anyone encountered this issue, or come across a suitable solution? I came across this post which is similar, but has no accepted answer from 6 months ago. Perhaps things have changed.
You can use the browser field in your package.json to configure a map similar to requireJS's paths map. See the browserify docs.
"browser": {
"jquery": "./vendor/jquery-1.42.js",
"./lib/ops.js": "./browser/opts.js"
}

Categories