How do I keep bower package dependencies out of my rollup bundle? - javascript

I'm currently creating a bower package that exports a single ES6 module.
When building the dist for my package, I'm using rollup to move all my internal modules into a single module, exporting only the one module.
Gulp task:
// Bundle ES6 modules into a single file
gulp.task('bundle', function(){
return gulp.src('./src/GuacaMarkdownEditor.js', {read: false})
.pipe(rollup({
// any option supported by rollup can be set here, including sourceMap
// https://github.com/rollup/rollup/wiki/JavaScript-API
format: 'es6',
sourceMap: true
}))
.pipe(sourcemaps.write(".")) // this only works if the sourceMap option is true
.pipe(gulp.dest('./dist'));
});
This all works fine, but I'm importing some dependencies from other bower packages which I don't want to bundle with my module (jQuery, font-awesome).
My problem is this: How can I keep bundling MY code and keep the ES6 import statements for bower packages - but without rollup bundling the external code into my bundle?
Example:
"use strict";
import $ from 'jquery'; // dont bundle this!
import GuacaAirPopUp from './GuacaAirPopUp'; // bundle this!
export
default class GuacaMarkdownEditor {
...
}

You can use this rollup plugin rollup-plugin-includepaths.
It allows you to import modules by name and define modules should be excluded from the bundle. I used it in a rollup.config.js:
import babel from 'rollup-plugin-babel';
import includePaths from 'rollup-plugin-includepaths';
var includePathOptions = {
paths: ['es6'],
include: {
'd3': './global/js/' + 'base/d3.min' // include library in es6 modules
},
external: ['d3'] // but don't bundle them into bundle.js
};
export default {
entry: './es6/entry.js',
plugins: [
includePaths(includePathOptions),
babel()
],
format: 'amd',
dest: 'build/bundle.js',
sourceMap: true
};
And in the es6 modules:
// not using relative path since it is handled by the plugin
import d3 from 'd3';
import other from 'otherModules';
//...
More discussion about external resolution here

It seems that rollup will detect named imports (as opposed to relative paths), as external dependencies.
When bundling this module:
import GuacaAirPopUp from './GuacaAirPopUp';
import ControlHandlerService from './ControlHandlerService';
import DefaultHandlerConfig from './DefaultHandlerConfig';
import toMarkdown from 'to-markdown';
import $ from 'jquery';
The bundler gave these messages:
Treating 'to-markdown' as external dependency
Treating 'jquery' as external dependency
When bundling the application that used this module, jquery was imported correctly using browserify.

Answered already by anthr however if you want to exclude your own made modules down below I believe is a clear explanation.
https://github.com/rollup/rollup/wiki/JavaScript-API#external
A list of IDs of modules that should remain external to the bundle
// main.js
import myMod from './my-module'; // <-- this module you don't wanna import
// build.js <--- gulp file
import * as path from 'path';
//...more of you gulp file code
rollup.rollup({
entry: 'app.js',
external: [
'./my-module', // <--- node module to be excluded from the bundle
path.resolve( './src/special-file.js' ) // <--- file you made to be excluded from the bundle
]
}).then(...)
//...more of you gulp file code
// Bundle ES6 modules into a single file
gulp.task('bundle', function(){
return gulp.src('./src/GuacaMarkdownEditor.js', {read: false})
.pipe(rollup({
// any option supported by rollup can be set here, including sourceMap
// https://github.com/rollup/rollup/wiki/JavaScript-API
format: 'es6',
sourceMap: true
}))
.pipe(sourcemaps.write(".")) // this only works if the sourceMap option is true
.pipe(gulp.dest('./dist'));
});

Related

Problems with some classes not exporting when it should have arose when porting codebase from Webpack to Rollup

So, I'm porting an old 2017 codebase from Webpack to Rollup for performance and code size reasons, also because of the old dependencies that the codebase used.
Unfortunately, The new Rollup version has a problem that I couldn't figure out a solution for. It doesn't seem to export some classes (In this case Engine and BackgroundLayer), but the Webpack unaltered version does. Is there a reason for this?
The Error in question:
Uncaught ReferenceError: Engine is not defined
Here's my rollup.config.js
import arraybuffer from '#wemap/rollup-plugin-arraybuffer';
import { babel } from "#rollup/plugin-babel";
import commonjs from "#rollup/plugin-commonjs";
import pkg from './package.json';
import resolve from "#rollup/plugin-node-resolve";
// import { terser } from "rollup-plugin-terser";
export default {
input: "src/index.js",
output: {
name: "index",
file: `dist/${pkg.name}.js`,
format: "umd",
},
external: ['ms'],
plugins: [
arraybuffer({ include: '**/*.dat' }), // so Rollup can import .dat files
resolve(), // so Rollup can find `ms`
commonjs(), // so Rollup can convert `ms` to an ES module
// terser(), // minifying
// babel configuration
babel({ exclude: 'node_modules/**', babelHelpers: "runtime", skipPreflightCheck: true }),
]
}
If anybody requires the full codebase, here are the two versions:
Webpack Code: https://github.com/kdex/earthbound-battle-backgrounds
Rollup Code: https://github.com/IamRifki/earthbound-battle-backgrounds-rollup
Figured it out, I had to call my bundle.js inside a module:
index.html
<script type="module">
import { BackgroundLayer, Engine } from "./bundle.js";
const engine = new Engine([new BackgroundLayer(153), new BackgroundLayer(298)]);
engine.animate();
</script>

Webpack is erroring when I attempt to import a directory containing modules

I'm trying to create a small npm library to make interfacing with an API a little neater. My folder structure is as follows...
dist/
index.js
src/
index.js
endpoints/
endpoint1.js
package.json
webpack.config.js
Within my src/index.js file I have..
import {endpoint1} from './endpoints'
module.exports = class lib {
...
}
When I npm run build (which runs webpack --display-error-details --mode production) webpack throws a big error saying "Module not found: Error: Can't resolve './endpoints' in 'my\project\dir\src'.
My webpack.config.js file currently looks like...
const path = require('path');
module.exports = {
mode: 'production',
entry: path.join(__dirname, '/src/index.js'),
output: {
path: path.resolve('dist'),
filename: 'index.js',
libraryTarget: 'commonjs2'
},
module: {
rules: [
{
test: /.js?$/,
exclude: /(node_modules)/,
use: 'babel-loader'
}
]
},
resolve: {
modules: [
path.resolve(__dirname, 'src/endpoints')
],
extensions: ['.js']
}
};
I can see similar questions have been asked before and the resolutions listed don't seem to work for me so I thought I'd post it incase im making a rookie error. If any more info is required just say! Sorry if it's fairly wall of texty. Thanks.
The correct import would be:
import endpoint1 from 'endpoint1';
By using resolve.modules you tell Webpack to look up non relative paths in that folder. The module name is "enpoint1".
But actually you should only do this with libraries that you use across your project, for an endpoint a relative import will be appropriate:
import endpoint1 from "./endpoints/endpoint1";
import {endpoint1} from './endpoints' means this:
import from file ./endpoints/index.js something that is exported under the name enpoint1 in that file. If you import directory then it refers to index.js under that directory, not to all other files. It doesn't exist in your setup.
Names inside {} refer to named imports. This goes only for es6 modules-style imports like import {...} from. If you ommit {} then you import the default. CommonJs-style imports like const {...} = require('') work differently. CommonJs does not have named imports and exports. It just will import default from that file and then fetch a field via object destructuring.
What you export is something unnamed(i.e. default) from file ./endpoints/enpoint1.js
Something is unnamed because you use module.exports = which is CommonJS-style export. CommonJS does not support named exports. This is equevalent to export default class lib ... in es6 modules-style exports.
IF you want to import many files under directory you can consider these solutions:
1) Often single import points are created. You make a index.js file. In it you import manually every file under the directoy that you want to export. Then you export it under names. Like this:
import a from './a.js';
import b from './b.js';
import c from './c.js';
export { a, b, c };
Then it will work
2) In some rare cases in might make sence to use fs.readdir or fs.readdirSync to scan the entire directory and dynamicly require files in a loop. Use it only if you must. E.g. db migrations.

Webpack alias in Laravel Mix to node_modules

I would like to use an alias in VUE.JS in a Laravel 5.8 project to import css and js I have in my module.
webpack.mix.js
mix.webpackConfig({
resolve: {
alias: {
'alias': path.resolve(
__dirname,
'~myModule/src'
)
}
}
});
In my VUE App.js I would like import the css folder and I wrote:
resources/js/app.js
// css files
import 'alias/lib/css'
// js files
import 'alias/lib/script'
But I'm wrong something becouse the alias is not resolved:
ERROR in ./resources/js/app.js
Module not found: Error: Can't resolve 'alias/lib/css' in...
Can you help me to fix the issue?
After so many attempts I got the issue. The code was good but I was missing to load the webpack.mix.js properly:
From Laravel Mix documentation:
The webpack.mix.js file is your entry point for all asset compilation. Think of it as a light configuration wrapper around Webpack. Mix tasks can be chained together to define exactly how your assets should be compiled.
But if you are using npm run watch it is not (re)loaded before to compile new changed assets. This means:
if you are in watch mode (npm run watch) exit and restart it to load new updated webpack.config.js if you changed it.
Finally it worked! And it resolve new alias properly!
Here the final config I used in webpack.config.js:
mix.webpackConfig({
resolve: {
alias: {
'aliasName': path.resolve(
__dirname,
'node_modules/MyModule/src/'
)
}
}
});
Another alternative is:
mix.webpackConfig({
resolve: {
modules: [
'node_modules'
],
alias: {
'aliasName' : 'MyModule/src/'
}
}
});
Then in my Vue component (or in vue app.js, just in case)
<template>
<myModule-component></myModule-component>
</template>
require('aliasName/lib/css'); // to load full css directory
require('aliasName/lib/script'); // to load full js directory
import MyModuleComponent from 'aliasName/widgets/MyModuleComponent.vue'
...
export default {
...
components: {
'myModule-component': MyModuleComponent
}

Set context dir for import when include some file in entry.js?

In entry.js file I have :
import 'index.js';
And that index.js has many imports from another dir like :
import test from 'modulename'.
But I have moved all modules to another dir and want to keep just index.js in main dir. So that's why I must rewrite all imports with new dir location like this :
import test from ../anotherdir/modulename
How to get rid of this and force webpack to search modules in new dir?
Now I am using webpack allias and this help me if path is too long but it still require to change all imports.
You can use resolve alias in webpack
Resolve
These options change how modules are resolved. webpack provides
reasonable defaults, but it is possible to change the resolving in
detail. Have a look at Module Resolution for more explanation of how
the resolver works.
webpack.config.js
module.exports = {
//...
resolve: {
alias: {
Utilities: path.resolve(__dirname, 'src/utilities/'),
Templates: path.resolve(__dirname, 'src/templates/')
}
}
};
Now, instead of using relative paths when importing like so:
import Utility from '../../utilities/utility';
you can use the alias:
import Utility from 'Utilities/utility';

How do you load typescript modules from node_modules using browserify?

When I run tsc, everything runs perfectly fine. However, I cannot understand how you are meant to import other typescript modules from node modules.
This is the important part of my gulp file:
gulp.task('compile-ts', ['clean'], function(){
var sourceTsFiles = [
config.allTs,
config.typings
];
var bundler = browserify({
basedir : "src",
debug : true})
.add("app.ts")
//.add("typings/tsd.d.ts")
.plugin(tsify);
return bundler.bundle()
.pipe(source("bundle.js"))
.pipe(gulp.dest("build"))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sourcemaps.write({includeContent: false, sourceRoot: 'src'}));
});
When I use,
import {DataRepository, List} from "tsmvc";
Where tsmvc is a typescript module node module, I get cannot find module tsmvc. Atom doesn't complain and shows me intellisense, tsc doesn't complain, but tsify does.
Can anyone point me to a gulp file doing something similar or explain the process?
Here's the github repo: https://github.com/Davste93/typescript-mvc-consumer/blob/master/gulpfile.js
Prior to version 0.15.3 of tsify, it was not possible to import TypeScript files from within node_modules.
Internally, the tsify plugin creates a transform and Browserify does not transform files under node_modules for non-global transforms. In version 0.15.3 of tsify, the global option was added and can be specified as follows:
var bundler = browserify({
basedir: "src",
debug: true
})
.add("app.ts")
.plugin(tsify, { global: true });

Categories

Resources