Building an Nx lib with Rollup does not bundle required dependencies - javascript

Question
I'm using the default Rollup executor to build an Nx library that I will later run in a browser-like environment. The resulting bundle cannot contain imports or requires. Running nx run ssr-bundle:build should create a single bundle containing both my application code and dependencies.
How can I bundle all of my code so my imported code is in the same file?
Example
The source file index.ts
import { isBoolean } from 'lodash';
async function handler() {
return new Promise((resolve) => {
setTimeout(() => {
resolve(isBoolean);
}, 1000);
});
}
export default handler;
The output file index.cjs.js
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var lodash = require('lodash'); <--------- this should be the lodash source code
async function handler() {
return new Promise((resolve) => {
setTimeout(() => {
resolve(lodash.isBoolean);
}, 1000);
});
}
exports["default"] = handler;

Related

Gulp browserify task stuck

Gulp terminal seems to get stucked after browserify-ing my main.js. Below is my gulpfile.babel.js
'use strict';
import gulp from 'gulp';
import gulpLoadPlugins from 'gulp-load-plugins';
import browserSyncLib from 'browser-sync';
import pjson from './package.json';
import minimist from 'minimist';
import glob from 'glob';
// Load all gulp plugins based on their names
// EX: gulp-copy -> copy
const plugins = gulpLoadPlugins();
const defaultNotification = function(err) {
return {
subtitle: err.plugin,
message: err.message,
sound: 'Funk',
onLast: true,
};
};
let config = Object.assign({}, pjson.config, defaultNotification);
let args = minimist(process.argv.slice(2));
let dirs = config.directories;
let taskTarget = args.production ? dirs.destination : dirs.temporary;
// Create a new browserSync instance
let browserSync = browserSyncLib.create();
// This will grab all js in the `gulp` directory
// in order to load all gulp tasks
glob.sync('./gulp/**/*.js').filter(function(file) {
return (/\.(js)$/i).test(file);
}).map(function(file) {
require(file)(gulp, plugins, args, config, taskTarget, browserSync);
});
// Default task
gulp.task('default', ['clean'], () => {
gulp.start('build');
});
// Build production-ready code
gulp.task('build', [
'browserify'
]);
// Testing
gulp.task('test', ['eslint']);
This is my browserify.js
'use strict';
import path from 'path';
import glob from 'glob';
import browserify from 'browserify';
import watchify from 'watchify';
import envify from 'envify';
import babelify from 'babelify';
import _ from 'lodash';
import vsource from 'vinyl-source-stream';
import buffer from 'vinyl-buffer';
import gulpif from 'gulp-if';
export default function(gulp, plugins, args, config, taskTarget, browserSync) {
let dirs = config.directories;
let entries = config.entries;
let browserifyTask = (files) => {
return files.map((entry) => {
let dest = path.resolve(taskTarget);
// Options
let customOpts = {
entries: [entry],
debug: true,
transform: [
babelify, // Enable ES6 features
envify // Sets NODE_ENV for better optimization of npm packages
],
paths: ['./node_modules','./src/_modules/', './src/Cwp/assets/PTM/scripts/', './src/_Cwp/assets/PTM/scripts/']
};
let bundler = browserify(customOpts);
if (!args.production) {
// Setup Watchify for faster builds
let opts = _.assign({}, watchify.args, customOpts);
bundler = watchify(browserify(opts));
}
let rebundle = function() {
let startTime = new Date().getTime();
bundler.bundle()
.on('error', function(err) {
plugins.util.log(
plugins.util.colors.red('Browserify compile error:'),
'\n',
err.stack,
'\n'
);
this.emit('end');
})
.on('error', plugins.notify.onError(config.defaultNotification))
.pipe(vsource(entry))
.pipe(buffer())
.pipe(plugins.sourcemaps.init({loadMaps: true}))
.pipe(gulpif(args.production, plugins.minify()))
.on('error', plugins.notify.onError(config.defaultNotification))
.pipe(plugins.rename(function(filepath) {
// Remove 'source' directory as well as prefixed folder underscores
// Ex: 'src/_scripts' --> '/scripts'
filepath.dirname = filepath.dirname.replace(dirs.source, '').replace('_', '');
}))
.pipe(plugins.sourcemaps.write('./'))
.pipe(gulp.dest(dest))
// Show which file was bundled and how long it took
.on('end', function() {
let time = (new Date().getTime() - startTime) / 1000;
console.log(
plugins.util.colors.cyan(entry)
+ ' was browserified: '
+ plugins.util.colors.magenta(time + 's'));
return browserSync.reload('*.js');
});
};
if (!args.production) {
bundler.on('update', rebundle); // on any dep update, runs the bundler
bundler.on('log', plugins.util.log); // output build logs to terminal
}
return rebundle();
});
};
// Browserify Task
gulp.task('browserify', (done) => {
return glob('./' + path.join(dirs.source, dirs.scripts, entries.js), function(err, files) {
if (err) {
done(err);
}
return browserifyTask(files);
});
});
}
When I execute gulp build in my terminal, below output is:
C:\Users\Chan\Downloads\Frontend\Frontend>gulp build
[23:25:23] Requiring external module babel-register
[23:25:25] Using gulpfile ~\Downloads\Frontend\Frontend\gulpfile.babel.js
[23:25:25] Starting 'browserify'...
[23:25:26] 842639 bytes written (1.21 seconds)
[23:25:27] 831961 bytes written (1.55 seconds)
./src/_Cwp/assets/PTM/scripts/main-contribute-form-iframe.js was browserified: 1.751s
./src/_Cwp/assets/PTM/scripts/main-vip-tree-iframe.js was browserified: 1.607s
[23:25:27] 1445674 bytes written (1.76 seconds)
./src/_Cwp/assets/PTM/scripts/main-plot-tree-iframe.js was browserified: 1.853s
[23:25:31] 7046431 bytes written (5.32 seconds)
./src/_Cwp/assets/PTM/scripts/main.js was browserified: 5.589s
The terminal looks stucked. what seems to be the problem here?

Why is does web pack bundle-size increase with imports?

I'm using webpack to bundle and deploy yet very simple JS functions to a cloud server. I thought of splitting them up into separate files rather than having them all in a single index.js.
My project structure basically looks like this:
src/
index.js
lib/
func.js
My webpack.config.js looks like this:
const Dotenv = require('dotenv-webpack');
module.exports = {
resolve: {
fallback: {
'os': false ,
'path': false,
'fs': false
}
},
mode: 'production',
entry: './src/index.js',
target: 'webworker',
plugins: [
new Dotenv()
]
};
The file func.js is:
export async function createUser({ args, graphql }) {
const { user } = args;
return { message: 'hello world!' };
}
Now I have bundled two versions of my index.js, at first I had the function directly included within the index.js:
// index.js including createUser()
async function createUser({ args, graphql }) {
const { user } = args;
return { message: 'hello' };
}
// add resolver to schema
self.addGraphQLResolvers({
"Mutation.createUser": createUser
});
which creates the bundle main.js
self.addGraphQLResolvers({"Mutation.createUser":async function({args:e,graphql:s}){const{user:r}=e;return{message:"hello"}}});
For the second attempt I had the function imported from the file func.js:
// index.js importing createUser()
const { createUser } = require('./lib/func.js');
// add resolver to schema
self.addGraphQLResolvers({
"Mutation.createUser": createUser
});
which generates
(()=>{var e={248:(e,r,t)=>{"use strict";async function o({args:e,graphql:r}){const{user:t}=e;return{message:"hello"}}t.r(r),t.d(r,{createUser:()=>o})}},r={};function t(o){var a=r[o];if(void 0!==a)return a.exports;var n=r[o]={exports:{}};return e[o](n,n.exports,t),n.exports}t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{const{createUser:e}=t(248);self.addGraphQLResolvers({"Mutation.createUser":e})})()})();
Both of them work but why is webpack doing this? Do I have a misconfiguration somewhere?
Thanks!

electron "MAIN" : requiring you own js file and call function from it

I'm can't understand some things here related to electron. I've been searching for hours for the magic answer but couldn't find anything.
My goal is simple. I don't want my main electron.js file to be 5000 lines long without any kind of organization so I'm trying to split the code into multiple js file that make sense.
My idea was to use import { someFunction1, someFunction2 } from './scripts/someScript' in my electron.js and then just creating that file with the arrow function in it and export them.
Then I could call the function as I want in the main file. However, it doesn't seem to be possible. I've read electronjs doesn't support ES6 syntax. I've read about Babel (But from what I read, it implies a bunch of additional configuration and I don't want to spend days trying to add this to the bunch of configuration that are already messy with electron + React (No boiler plate here). And I didn't find anything specifics for this combo.
Question is. Is this doable in 2021? Am I missing anything? What would you guys recommend?
File would look something like this:
import { someNodeModuleFunction } from 'someNodeModule';
const someFunction1 = () => {
return 1;
};
const someFunction2 = () => {
return 2;
};
export { someFunction1, someFunction2 }
EDIT
Here's the actual code I have a problem with. I still get
if the file is .js: "Must use import to load ES Module"
If the file is .mjs: "Cannot use import statement outside a module"
This script is simply using fs to create a directory:
DataManagement.mjs:
import { existsSync, mkdir } from 'fs';
const electron = require('electron');
const app = electron.app;
const documentFolder = app.getPath('documents');
const CreateDataDirectory = () => {
const mainPath = documentFolder + 'AppName'
if (!existsSync(mainPath)) {
mkdir(mainPath);
}
};
module.exports = { CreateDataDirectory }
Calling it like that in electron.js:
const { CreateDataDirectory } = require('./scripts/DataManagement.mjs');
[...]
CreateDataDirectory()
Not sure how dividing the code can be that hard. :)
You may need to use Node.js module syntax (require and module.exports) or Babel (code transpiler).
For example:
import { someNodeModuleFunction } from 'someNodeModule';
const someFunction1 = () => {
return 1;
};
const someFunction2 = () => {
return 2;
};
module.exports = { someFunction1, someFunction2 }
Using your module:
const { someFunction1, someFunction2 } = require ('./FILE.js');
// ...
You could use module.exports:
otherModule.js
const someFunction1 = () => {
return 1;
};
const someFunction2 = () => {
return 2;
};
module.exports = {
someFunction1,
someFunction2
};
main.js
const { someFunction1, someFunction2 } = require('otherModule.js');

Require not behaving as expected

I'm using the proxyquire library, which mocks packages on import.
I'm creating my own proxyquire function, which stubs a variety of packages I use regularly and want to stub regularly (meteor packages, which have a special import syntax):
// myProxyquire.js
import proxyquire from 'proxyquire';
const importsToStub = {
'meteor/meteor': { Meteor: { defer: () => {} } },
};
const myProxyquire = filePath => proxyquire(filePath, importsToStub);
export default myProxyquire;
Now I want to write a test of a file which uses one of these packages:
// src/foo.js
import { Meteor } from 'meteor/meteor'; // This import should be stubbed
export const foo = () => {
Meteor.defer(() => console.log('hi')); // This call should be stubbed
return 'bar';
};
And finally I test it like this:
// src/foo.test.js
import myProxyquire from '../myProxyquire';
// This should be looking in the `src` folder
const { foo } = myProxyquire('./foo'); // error: ENOENT: no such file
describe('foo', () => {
it("should return 'bar'", () => {
expect(foo()).to.equal('bar');
});
});
Note that my last 2 files are nested inside a subfolder src. So when I try to run this test, I get an error saying that the module ./foo couldn't be found, as it is being looked for in the "root" directory, where the myProxyquire.js file is, not the src directory as expected.
You might be able to work around that (expected) behaviour by using a module like caller-path to determine from which file myProxyquire was called, and resolving the passed path relative to that file:
'use strict'; // this line is important and should not be removed
const callerPath = require('caller-path');
const { dirname, resolve } = require('path');
module.exports.default = path => require(resolve(dirname(callerPath()), path));
However, I have no idea of this works with import (and, presumably, transpilers).

Using Gulp to create browser friendly js file, including imports

Isomorphic React
I would like to transpile my react components server side into one bundle.min.js file. The issue I am having is that the file doesn't resolve import statements.
This is the file I would like to transpile (client/component.js)
import React from 'react';
import ReactDom from 'react-dom';
import App from './components/app';
ReactDom.render(<App />, document.getElementById('app'));
The result is this (bundle.min.js)
'use strict';
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _reactDom = require('react-dom');
var _reactDom2 = _interopRequireDefault(_reactDom);
var _app = require('./components/app');
var _app2 = _interopRequireDefault(_app);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
_reactDom2.default.render(_react2.default.createElement(_app2.default, null), document.getElementById('app'));
But this is not what I want.
Files I require
I need all the import statements removed and replaced with the actual files that I need. In my case I require
some files from node modules
some component files
Gulp function so far
// builds the components and clientside
gulp.task('buildComponentsClient', () =>
gulp.src(['./client/*.js'])
.pipe(include()).on('error', console.log)
.pipe(babel({ presets: ['es2015', 'react']}))
.pipe(concat('bundle.js'))
// .pipe(uglify({mangle: false}))
.pipe(rename('bundle.min.js'))
.pipe(gulp.dest('./public'))
);
Question
How do i create a browser friendly file with all dependencies that are specified in these minimalistic react element files?
From what I understand you wan't to use browserify coupled with babelify. Here is my gulp task for this:
import gulp from 'gulp';
import glob from 'glob';
import browserify from 'browserify';
import babelify from 'babelify';
import rename from 'gulp-rename';
import source from 'vinyl-source-stream';
import es from 'event-stream';
import uglify from 'gulp-uglify';
import buffer from 'vinyl-buffer';
const path = './client/';
const files = '*.js';
const bundles = [path + files]; // I use an array to be able to bundle
// multiple paths within the same task
gulp.task('bundle', () => {
let bundleAll = bundles.map(bundle);
return Promise.all(bundleAll); // Task ends when all bundles are done
});
// Bundle files found in bundlePath, returns a Promise resolved
// when all files have been processed
function bundle(bundlePath) {
return new Promise((resolve, reject) => {
glob(bundlePath, (err, files) => { // Create glob from path
var tasks = files.map(file => { // loop through each file
return browserify(file) // pass it to browserify
.transform(babelify, ["es2015", "react"]) // using babelify (browserify + babel)
.bundle() // ..profit!
.on('error', err => {
console.error('err', err.toString());
reject(err);
})
.pipe(source(file)) // this is required for browserify output to be use as a gulp stream
.pipe(buffer()) // needed by gulp-uglify
.pipe(uglify())
.pipe(rename({ 'bundle.min.js' }))
.pipe(gulp.dest('./public'));
});
es.merge(tasks).on('end', resolve); // When all files have been processed, resolve the promise we returned
});
});
}

Categories

Resources