How do I execute/bundle JS with Webpack from another task runner? - javascript

I've been using webpack for my latest projects, but I have legacy projects using grunt or gulp or other.
In those cases, I'd still love a bundler like webpack with ultra minimal configs to use ES6 imports and such.
How do I execute a single webpack bundle command from within say gulp or longrunning node script?
I can spawn a subprocess and call webpack but I'm curious how I'd use it in legacy toolchains via JS.
webpack({...}) // does nothing
I found the use of webpack().apply() on some other stack overflow post and webpack does compile once, but not a second time when called within a gulp task.
(function exampleCreateBundle() => {
const compiler = webpack({
entry: './_js/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'js')
}
});
compiler.apply(new ProgressPlugin(function(percentage, msg) {
console.log((percentage * 100) + '%', msg);
}));
// works once
})();
Thanks for any help!
Update:
Honestly, I'm just spawning a child process and running npx webpack.
At this point the question is academic.

Related

Combine, Minify, and convert to ES5 with WebPack and Babel

I have a project that works perfect and was written in TS, I had to convert it to plain JS and it works for the most part. The issue where I am struggling is removing the default WebPack loader after the files have been combined and minified, WebPack includes a loader to the final output even thought I do not need a loader since all the files are combined into one large file.
+ filea.js
+ fileb.js
+ filec.js
+ filed.js
-> output bundle.js
I have read a few articles/posts that recommend manually creating a config file providing the name of each of the files that will combined and minified, this may work OK but the problem is that the project I am working on is broken into small chunks (modules) so that tools such WebPack can be smart enough and know when a file should be added as a dependency in the final output.
I know we can combine and minify multiple individual JS files but when it comes to exporting a single file it seems like the task is trivial With TS but in the vanilla JS world there is little or no information about the subject.
I don't understand something, do you want to have one big file or small individual modules (chunks)?
An example of small modules:
module.exports = {  
entry: {    
app: './src/app.js',
admin: './src/admin.js',
contact: './src/contact.js'  
}
};
Another method is one main module and it contains all smaller modules.
module.exports = {  
entry: {    
app: './src/app.js'  
}
};
You can also use something like lazy loading. Then the modules (chunks) will be dynamically loaded only when needed. lazy-loading
Here is an example of using several entries webpack-boilerplate.
Sounds like you have a project with several JS files and you want to use webpack to bundle all of them and minify the result.
Webpack was built for this.
You'll need to add a build step in your package.json like this:
"scripts": {
"build": "webpack --config prod.config.js"
}
Then you'll need to create a webpack.config.js with a module.exports block that has an entry point and rules to include in your project. The following should be a minimal setup that can get your started:
const path = require('path');
module.exports = {
entry: "./your/path/to/src",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js"
},
module: {},
plugins: [
new MinifyPlugin(minifyOpts, pluginOpts)
]
}
You can add modules that perform additional code transpilation for files that matcha a certain regex. You can also use a plugin to perform minification such as babel-minify-webpack-plugin as documented here https://webpack.js.org/plugins/babel-minify-webpack-plugin/. (Note you will need to add this dependency.)
The full webpack configuration can be found here: https://webpack.js.org/configuration/

Set environment mode and output messages when starting a gulp task

I'm wondering how I can output messages to the terminal when I run a gulp process and how I can set an environment to run tasks in specific ways.
I'm sure I've seen something like gulp scripts:dev before but don't know how to use, can anyone advice how I can do this?
How would you run the default task this way, gulp deafult:dev?
Is it possible to ask the user which environment they want to run the task for in the terminal when the execute the gulp command, if they don't specify it.
I've used the gulp-if plugin to achieve this but it works slightly differently, you need to set a node environment variable before running gulp i.e. NODE_ENV=dev gulp.
var gulp = require('gulp'),
sass = require('gulp-ruby-sass'),
gulpif = require('gulp-if'),
shell = require('gulp-shell');
var isDev = process.env.NODE_ENV === 'dev';
// gulp-shell task to output messages to terminal
gulp.task('info', shell.task([
'echo run in developer mode with this command: NODE_ENV=dev gulp'
]));
// Styles Task
// Uses gulp-if plugin to run task differently dependent on env.
gulp.task('styles', ['info'], function () { // eslint-disable-line strict
return sass('css/sass/*.scss', {
style: gulpif(!isDev,'compressed','expanded'),
cacheLocation: 'css/sass/.sass-cache',
sourcemap: isDev
})
[...code ommitted...]
});
gulp.task('default', ['h','styles']);
Also I've used gulp-shell above to output messages to the terminal, but it's pretty basic. Is there anyway I can do something similar with line breaks and colours with the message I output to the terminal.
Take a look at gulp-environments - you can set as many as you like but dev and prod are sufficient for most. You can define each in the gulpfile and set different events to occur from within each gulp script. So your styles script can contain a .pipe(dev(some dev only sourcemap code))and a .pipe(prod(some mini fixed build code)). You can run the script from git bash with an --env flag... gulp --env dev or gulp --env prod. And run two completely different build cycles from more or less the same script. You set your default gulp task to run all your page scripts and it will only execute the ones for each environment as it loops.
To output messages to the terminal you can require gulp-util node module.
Example code:
gulp.task('test', () => {
gutil.log(gutil.colors.yellow('=== Testing ==='));
});

Best way to manage express server dependencies in production env

I’ve developed an application with a react front end and a node server on the backend. The React dependencies are bundled by webpack into bundle.min.js, but when I put my server.js on a container/VM wherever, how do I ensure its dependences (i.e. express, winston, body-parser, etc) are installed.
npm install --production
will install my production dependences on the server but this will include everything from react, react-dom, d3, etc.
I have tried using a separate webpack configuration to make a server bundle, along the lines of,
{
name: 'server',
target: 'node',
entry: path.resolve(__dirname, 'src', 'server', 'app.js'),
devtool: 'cheap-module-source-map',
output: {
path: path.resolve(__dirname, 'dist', 'server'),
filename: 'server.bundle.js'
}
},
node: {
__dirname: false
}
but when I start the server I am getting a Cannot Get / error.
What is the best method to install only the dependencies related to my express server for a production build?
Unless you are potentially going to run out of file space, I don't think its a problem to have all of your dependencies installed. It certainly makes maintainability simpler vs creating two separate projects. What advantage do you get from trying to only install production packages on your server? Or better yet, what disadvantage is there to having all of them?

Why are we requiring React and ReactDOM as modules when working with Webpack? It takes long to produce output

EDIT: I WAS WRONG. I'M USING GULP, WEBPACK AND BABEL, SEE MY ANSWER.
I've just begun learning React. Basically all tutorials I've seen use Webpack and babel.
Webpack and babel are great but why do most require react and react-dom as modules to be packaged with the webpack bundle file?:
var React = require('react');
var ReactDOM = require('react-dom');
The cdn files that we can load instead of making react go through webpack found right at the bottom of react's installation page https://facebook.github.io/react/docs/installation.html are much smaller than the react modules that webpack outputs (at least for me and I've done recommended optimizations).
The page has these script tags:
Development files (react 29kb, react-dom 137kb):
<script src="https://unpkg.com/react#15/dist/react.js"></script>
<script src="https://unpkg.com/react-dom#15/dist/react-dom.js"></script>
Production files (.min.js) (react 7kb, react-dom 36kb):
<script src="https://unpkg.com/react#15/dist/react.min.js"></script>
<script src="https://unpkg.com/react-dom#15/dist/react-dom.min.js"></script>
The production files total 43kb and the development files total 166kb.
Using webpack I've managed to get react and react-dom down to 220kb.
For me it's not so much about the size of the files when they are loaded into the browser, at least not during development.
The cdn files will make React and ReactDOM global variables, which really is fine but I guess it would be nicer to have them be local to a module function like the tutorials, it's not like there's going to be a global identifier collision though. The problem is the fact that when we require the react.js npm module it itself has many requires in it and so on and it gets run through webpack and babel which takes a few seconds just to produce the bundle file each time we make a change during development because react is very big. The fact that we can minimize the output of react with webpack's config doesn't change the fact that webpack will take a while to produce the minimized output. When I make a simple change to my app.js and want the bundle file to be ready as quickly as possible.
If I use the react cdn files and only have my own app code be bundled with webpack a change in my app.js is pretty much bundled instantly as opposed to requiring react which will then take about 4-5 seconds to bundle.
Does anyone have a solution to this other than using the cdn? Could I possibly be using webpack in the wrong way?
Thanks!
Solved it!
As Lucas Katayama pointed out in a comment under my question, webpack dev server will only reprocess the files that have changed. Therefore it won't have to process React and ReactDOM more than once I believe.
I'm not using the webpack dev server. I don't want to. I'm simply using my own node server file and I'm using Gulp to do all the build of various things in my project. The bundling happens though webpack-stream https://www.npmjs.com/package/webpack-stream
What I was doing wrong was that I was watching all my javascript files for any changes and then running the whole webpack process every time (watching file changes using gulp-watch). This is what I had in my gulp file when it was running slow (reprocessing react):
var gulp = require('gulp');
var watch = require('gulp-watch');
var webpack = require('webpack-stream');
var webpackConfig = require('./webpack.config');
var browserSync = require('browser-sync').create();
gulp.task('js', function() {
return watch('./src/js/**/*.js', function () {
return gulp.src('./src/js/app.js')
.pipe(webpack(webpackConfig))
.pipe(gulp.dest('./dist/js/'))
.pipe(browserSync.reload({stream: true}));
});
});
What I had to do was stop watching my js files with gulp watch and I had to put a new option in my webpack.config.js file, the option's name is "watch" it has to be set to true. Now my gulp js task looks like this:
gulp.task('js', function() {
return gulp.src('./src/js/app.js')
.pipe(webpack(webpackConfig))
.pipe(gulp.dest('./dist/js/'))
.pipe(browserSync.reload({stream: true}));
});
My webpack.config.js file looks like this:
module.exports = {
watch: true,
output: {
filename: "bundle.js"
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader",
query: {
presets: ["latest", "react"],
plugins: [
"react-html-attrs",
"transform-class-properties",
"transform-decorators-legacy"
]
}
}
]
}
};
It is MUCH faster now. Thanks for the comment Lucas!

react js with browserify

I start to learn react js and they say on the react website "We recommend using React with a CommonJS module system like browserify"
So I used browserify with a simple hello world react component. Finally it produces an output file bundle.js of 651 ko (just for a simple hello world).
With this file bundle.js, I no longer have to include the scripts react.js and react-dom.js in my webpage, so I concluded that the file bundle.js includes my component and the react library.
But if I creates many components, I will have some javascript files and after the browserify transformation, each output files will be big because each files contains the react library. it will produce only one output file.
So I don't understand why they recommend to use browserify rather than just include react.js and react-dom.js library into my webpage and also my components js files after a babel transformation?
For development it is better not to minify. You apply minify when you go to production. For example with gulp;
gulp.task('appjs', function(){
browserify({ debug: true })
.transform(babel.configure({stage: 0}))
.require(source.appjs, { entry: true })
.bundle()
.pipe(vsource('app.min.js'))
.pipe(gulp.dest('./ui-dist'));
});
gulp.task('buildapp', function(){
browserify({ debug: false })
.transform(babel)
.require(source.appjs, { entry: true })
.bundle()
.pipe(vsource('app.min.js'))
.pipe(vbuffer())
.pipe(uglify())
.pipe(gulp.dest('./ui-dist'));
});
I think your question is about the size of the bundle file (the resulted file of browserify build), you worry about the time it will take when loaded on the page. This is some really important things you should know :
1. you don't have to include all your files in one bundle : you can generate multiple bundles. For example, you can configure browserify to create one bundle for your vendor files, and one or multiple bundles for your components.
in Dev mode, you don't have to minify your bundle,
For prod, you should generate your bundle using the react prod mode and minification.
To achieve point 1 (multiple bundles), here is an example with grunt browserify plugin.
var jsFiles = {
jsSrcFiles: './src/main/js/vs/**/*.js*', // my js and jsx source files
jsLibs: [
// vendor libs that I want to put in separate bundle
'react/addons',
...
]
};
...
browserify: {
app: {
options: {
transform: ['reactify'],
extensions: ['.jsx'],
// Here is where I tell browserify not to bundle vendor files with my source files
external: jsFiles.jsLibs
},
src: [jsFiles.jsSrcFiles],
dest: buildParams.js + '/vs_app.js'
},
// here is where I build vendor files in separate bundle named vendor.js
vendor: {
src: ['.'],
dest: buildParams.js + '/vendor.js',
options: {
alias: jsFiles.jsLibs
}
}
}...
Browserify is a great tool when it comes to small projects, when your project becomes more complex, browserify config tends to be very complex. In order to have more control of your built bundles, I recommend to use webpack, which is also a tool that facebook recommends. It allows easy bundling customization...

Categories

Resources