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
});
});
}
Related
I am using webpack 5.12.3 for bundle split.
He is my webpack.config.js
const { resolve } = require('path')
const webpack = require('webpack')
const TerserPlugin = require('terser-webpack-plugin')
const ProgressBarPlugin = require('progress-bar-webpack-plugin')
const { getIfUtils, removeEmpty } = require('webpack-config-utils')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const CompressionPlugin = require("compression-webpack-plugin");
module.exports = env => {
const { ifProduction, ifNotProduction } = getIfUtils(env)
const mode = ifProduction('production', 'development')
return {
mode,
//context: resolve('./src/public/js'),
entry: {
index: './.dist/public/main.js',
},
output: {
filename: '[name].min.js',
chunkFilename: '[name].min.js',
path: resolve('./src/public/js/'),
pathinfo: true,
},
}
remaining code contains rules,optimzations,minimizers etc.
Here is main.js which is used in webpack config entry
import 'babel-polyfill';
var Routes = require('../routes/react.jsx');
var Client = require('react-engine/lib/client');
// Include all view files. Browerify doesn't do
// this automatically as it can only operate on
// static require statements.
// Not required as part for webpack.
//require('./views/**/*.jsx', {glob: true});
// boot options
var options = {
routes: Routes,
// supply a function that can be called
// to resolve the file that was rendered.
viewResolver: function viewResolver(viewName) {
return require('./views/' + viewName);
}
};
document.addEventListener('DOMContentLoaded', function onLoad() {
console.log(typeof(options));
console.log(options);
Client.boot(options);
});
Here for all pages in application this code is getting executed only one bundle file is created. My aim is to have separate bundle for every page in /src/views . I did try to get viewName from viewResolver its not getting executed . Can anyone please suggest me how should I change code so that I can have entry for every page (that is possible using entry section of webpack config) but as everything is coming to main.js . If I try to add another main1.js what should be its code and how execution should come there ?
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?
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;
I'm using Jest to test my api calls file, when I run a simple test I've got an error Cannot find module 'config' from 'api.service.js' which is an import at the top of my api.service.js file:
//api.service.js
import config from "config"; //get data from my webpack.config.js
export const apiService = {getmyData};
function getmyData() {
let queryString = `${config.API}/api/datacall`;
return new Promise(
(resolve, reject) => {
client.get(`${config.API}/api/datacall`).then(result => {
return resolve(result );
});
},
error => {
return reject(error);
}
);
}
Test File in the same folder as the above
//api.spec.js
import getmyDatafrom "./api.service";
const domain = "http://fakeapi.com";
const mockedConsolelog = jest.spyOn(global.console, "log");
const mockedConsoleerror = jest.spyOn(global.console, "error");
Why can't my test file get to my config like the api.service.js?
You probably have to do the import with a relative path.
import config from "./config";
Otherwise, it tries to import something from an npm module called config.
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).