How to setup webpack for supporting ES6 Modules in Node - javascript

I'm using Webpack for bundle client and server code, so my webpack.config.js looks like:
module.exports = [
{ /* client config */ },
{ /* server config */ },
];
I want to write ES6 (modules) in both and transpile code to ES5 using Babel.
For client, this can be done with babel-loader:
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: [
'react',
[
'env',
{
targets: {
'browsers': 'last 2 versions',
},
},
],
],
},
}
Based on this, I wrote babel loader for server:
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: [
'react',
[
'env',
{
targets: {
'node': 'current',
},
},
],
],
},
}
Something tells me that babel-loader will never work for this purpose.
After ran webpack, bundles are right located but server entry point (server.js) aren't transpiled correctly:
SyntaxError: Unexpected token import
Generally when we want to transpile Node code, we would use babel-cli package and add a script in package.json:
"scripts": {
"build": "babel src -d dist"
}
and manually:
npm run build
My question is: How to setup ES6 transpiling with Babel for Node inside webpack.config.js?
+BONUS
webpack.config.js
const path = require('path');
const babelRcClient = {
presets: [
'react',
[
'env',
{
targets: {
'browsers': 'last 2 versions',
},
},
],
],
};
const babelRcServer = {
presets: [
'react',
[
'env',
{
targets: {
'node': 'current',
},
},
],
],
};
const babelLoaderClient = {
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: babelRcClient,
};
const babelLoaderServer = {
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: babelRcServer,
};
module.exports = [
{
context: __dirname,
entry: './shared/index.js',
output: {
path: path.resolve(__dirname, './static'),
filename: 'bundle.js',
},
module: {
loaders: [
babelLoaderClient,
],
},
plugins: [],
},
{
context: __dirname,
entry: './server/server.js',
target: 'node',
output: {
path: path.resolve(__dirname, './build'),
filename: 'server.js',
libraryTarget: 'commonjs',
},
externals: [ /^(?!\.|\/).+/i, ],
module: {
loaders: [
babelLoaderServer,
],
},
plugins: [],
},
]

By specifying
targets: {
'node': 'current',
}
you are telling babel to transpile your code to node version which you are using to transpile the code.
Are you using the same node version on production?
Try specifying numeric node version, e.g. 6.11.2 and then run transpilation.
Another thing you can do is tell babel to leave ES6 modules in ES6 way and don't replace it with commonjs approach (which is default) by setting:
targets: {
'node': ...,
},
modules: false

This thing worked for me. Try and check once.
{
test: /\.(js|jsx)$/,
include: [].concat(
path.resolve('./app') //path to your application
),
use: ['babel-loader']
}

Related

Webpack: include specific file instead of package.json specified?

I have a webpack configuration:
var path = require("path");
module.exports = {
entry: {
app: [
'./src/index.js'
]
},
output: {
path: path.resolve(__dirname + '/dist'),
filename: '[name].js',
},
module: {
rules: [
{
test: /\.(css|scss)$/,
use: [
'style-loader',
'css-loader',
]
},
{
test: /\.js$/,
exclude: /node_modules/,
},
{
test: /\.html$/,
exclude: /node_modules/,
loader: 'file-loader?name=[name].[ext]',
},
{
test: /\.elm$/,
exclude: [/elm-stuff/, /node_modules/],
loader: 'elm-webpack-loader?verbose=true&warn=true',
options: {debug: true, warn: true},
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url-loader?limit=10000&mimetype=application/font-woff',
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file-loader',
},
],
noParse: /\.elm$/,
},
devServer: {
inline: true,
stats: { colors: true },
},
};
I have a few questions:
According to me the above config says that it should not be looking
for js files in node_modules. However it is still bundling
./node_modules/dexie/dist/dexie.es.js when I call require ("dexie"). (I am just doing this to experiment and understand webpack).
I would rather like to call dexie.js instead of dexie.es.js. How do
I make this happen. I know I can set the mainFields property.
However how do I do this on a prelibrary basis instead of globally.
Not sure if I understand your requirement fully, but an option is to set up aliases in the webpack resolve
module.exports = {
entry: {
...
},
output: {
...
},
module: {
rules: [
...
],
noParse: /\.elm$/,
},
resolve: {
alias: {
dixie: 'node_modules/dexie/dist/dexie.js'
}
},
devServer: {
...
},
};
To your first question please see here. It has already been answered.
No matter what you exclude in your loaders config, the file will be bundled unless you define it as external in your config.
To your second question, you can just require the other file with
require('dexie/dexie.js')
When you just write require('dexie'), webpack will look in your node_modules folder for a folder named 'dexie', read the package.json and resolve the file described by the module property. This is described here.
For more info, please read the webpack docs. They are excellent.

Webpack2 + babel all but one js file are converted to es5

I'm using webpack and babel to convert my js and vue2 files to es5 and compile into a single build.js
This is my .babelrc
{
"presets": ["latest", 'stage-1'],
"plugins": [
"transform-runtime",
"transform-es2015-arrow-functions"
],
"comments": false
}
and webpack.config.js
var path = require('path'),
webpack = require('webpack');
require("babel-polyfill");
module.exports = {
entry: ['babel-polyfill', './src'],
output: {
path: './dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
scss: 'style-loader!css-loader!sass-loader',
styl: 'style-loader!css-loader!stylus-loader'
}
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.styl$/,
use: [
'style-loader',
'css-loader',
{
loader: 'stylus-loader',
},
],
}
]
},
resolve: {
modules: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules')
],
alias: {
vue: 'vue/dist/vue.common.js'
},
extensions: ['.js', '.vue']
},
plugins: [
// new webpack.DefinePlugin({
// 'process.env': {
// 'NODE_ENV': JSON.stringify('production')
// }
// })
]
}
Running the following command, successfuly compiles all js and vue files including the imported ones into build.js
./node_modules/webpack/bin/webpack.js --progress --watch --display-error-details
All es6 compatible codes are converted to es5 except for BaseModal.js in https://github.com/vue-bulma/modal/
BaseModal.js resides in node_modules/vue-bulma-modal/src/ and is imported by Modal.vue in the same package
I import Modal over index.js of the same package by
import {Modal} from 'vue-bulma-modal'
and BaseModal.js ends up in build.js as it is, without being converted to es5.
But if i copy Modal.vue and BaseModal.js directly into my code and update the import paths accordingly , it is converted to es5 just fine without any problems.
What is it that I'm doing wrong in my webpack.config.js?

Cannot find module, but module exists and is not required by this bundle

I have an Express server with a React client-side app, I set up my webpack config to output two bundles, one for my server and one for my react app.
I cannot compile my server bundle unless I comment out the shebang at the start of bin/www. If I do comment it out and compile everything I can't start the server because I get this error:
Error: Cannot find module 'querystring'.
at /Users/jahansj/Documents/personal-projects/roomshake/app_dist/js/app_bundle.js:51283:42
Query string is installed, saved as a dependency and I can see it in my node_modules folder.
I have tried not excluding node_modules from my webpack config as well as using a shebang loader in babel to see if commenting out the shebang was causing the problem somehow.
This is my webpack.config.js:
module.exports = [{
name: 'dev',
entry: './dev/js/main.js',
output: {
path: 'dist/js',
filename: 'bundle.js'
},
module: {
loaders: [
{
test: /\.js?$/,
exclude: (/node_modules/ || /app/),
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
},
{
test: /\.css$/,
loaders: [
'style?sourceMap',
'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]'
]
}
]
}
},
{
name: 'app',
target: 'node',
entry: './app_dev/bin/www',
output: {
path: 'app_dist/',
filename: 'app_bundle.js'
},
module: {
loaders: [
{
test: /\.js?$/,
exclude: (/node_modules/ || /dev/),
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
},
{
test: /\.json$/,
loader: 'json-loader'
}
]
}
}];

Webpack includes unused library in bundle.js

I don't understand why...
Include like 100Kbytes of a unused library:
/*!
* The buffer module from node.js, for the browser.
*
* #author Feross Aboukhadijeh <feross#feross.org> <http://feross.org>
* #license MIT
*/
...
...
My webpack.deploy.config.js
'use strict';
/* eslint-env node */
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const config = {
addVendor: function (name, path) {
this.resolve.alias[name] = path;
this.module.noParse.push(new RegExp(`^${name}$`));
},
node: {
Buffer: false,
global: false,
process: false,
setImmediate: false
},
entry: {
app: [
'./src/main.jsx'
],
vendors: [
'jquery',
'semantic',
'semantic.css',
'react',
'react-dom'
]
},
resolve: { alias: {} },
output: {
path: `${__dirname}/build`,
publicPath: '/',
filename: 'bundle.js'
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new CopyWebpackPlugin([{ from: './src/static', to: './' }]),
new webpack.optimize.CommonsChunkPlugin('app', null, false),
new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.js'),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
],
module: {
noParse: [],
loaders: [
{
test: /\.(jsx)?$/,
exclude: /node_modules/,
loader: 'babel'
},
{
test: /\.(js)$/,
loader: 'babel',
exclude: [/node_modules/, /bower_components/]
},
{
test: /\.(css)$/,
loader: 'style!css'
},
{
test: /\.(scss)$/,
loader: 'style!css!sass'
},
{
test: /\.(less)$/,
loader: 'style!css!less'
},
{
test: /\.(png|woff|woff2|eot|ttf|svg)$/, loader: 'url-loader?limit=100000'
}
]
}
};
config.addVendor('jquery', `${__dirname}/bower_components/jquery/dist/jquery.min.js`);
config.addVendor('semantic', `${__dirname}/bower_components/semantic/dist/semantic.min.js`);
config.addVendor('semantic.css', `${__dirname}/bower_components/semantic/dist/semantic.min.css`);
config.addVendor('react', `${__dirname}/bower_components/react/react.min.js`);
config.addVendor('react-dom', `${__dirname}/bower_components/react/react-dom.min.js`);
module.exports = config;
I am using es6 with babel and react, the code works well, just trying to minify the package.
Also uses a cross library (node/browser) that use http and https, but I think its not the problem.
I faced the similar problem when migrated from webpack1 to webpack2. The bundle size increased from 125kb to 164kb (minimized).
Looks like the major part takes the buffer library which presumably comes from css-loader and adds source-map support.
I opened an issue https://github.com/webpack-contrib/style-loader/issues/194 and looks like the simple workaround is to add node: {Buffer: false} to the webpack config. Read more at: https://webpack.js.org/configuration/node/

How Can I Exclude Spec Files from Code Coverage with Karma using Webpack and Babel?

Problem
I'm working on a small react-redux project configured with webpack, babel, and karma. I added code coverage to karma, but I couldn't find a way to exclude the test files from coverage. So my code coverage has spec files.
How can I exclude these spec files from coverage?
I tried to use a regex expression to exclude the spec files, but since it was being loaded by webpack, it didn't work.
tests.webpack.js
const context = require.context('./src', true, /.+\Spec\.js$/);
context.keys().forEach(context);
module.exports = context;
webpack.config.js
module.exports = {
entry: './src/index.js',
output: {
path: __dirname,
filename: 'dist/bundle.js'
},
devtool: 'source-map',
resolve: {
extensions: ['', '.js', '.scss'],
modulesDirectories: [
'node_modules',
'src'
]
},
module: {
preLoaders: [
{
test: /\.js$/,
loader: 'eslint-loader',
exclude: /node_modules/
}
],
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
],
},
};
karma.config.js
var path = require('path');
module.exports = function (config) {
config.set({
browsers: ['PhantomJS'],
singleRun: true,
frameworks: ['mocha', 'sinon-chai'],
files: [
'tests.webpack.js'
],
preprocessors: {
'tests.webpack.js': ['webpack', 'sourcemap']
},
reporters: ['mocha', 'osx', 'coverage'],
webpack: {
module: {
preLoaders: [
{
test: /\.js$/,
exclude: [
path.resolve('src/'),
path.resolve('node_modules/')
],
loader: 'babel'
},
{
test: /\.js$/,
include: path.resolve('src/'),
loader: 'isparta'
}
]
}
},
webpackServer: {
noInfo: true
},
coverageReporter: {
type: 'html',
dir: 'coverage/'
}
});
};
This is how I do it on my project, where I have all my tests in __test__ folders included with each component. You should be able to change this to a regex something like this /\.spec.js$/.
karmaConfig.webpack.module.preLoaders = [{
test : /\.(js|jsx)$/,
include : new RegExp(config.dir_client),
loader : 'isparta',
exclude : [
/node_modules/,
/__test__/,
],
}];
In your case you need to add exclude to this bit of your config.
{
test: /\.js$/,
include: path.resolve('src/'),
loader: 'isparta'
}
I solved this by filtering out the results I didn't want by placing a .filter() before the .forEach(context).
const includes = require('lodash/includes');
const context = require.context('./src', true, /\.test\.js$/);
context.keys()
.filter(file => includes(file, './api/') === false)
.forEach(context);
You could also write it directly into the .forEach().
const includes = require('lodash/includes');
const context = require.context('./src', true, /\.test\.js$/);
context.keys()
.forEach(file => {
if (includes(file, './api/') === false) {
context(file);
}
});
If you don't use Lodash, you can use:
file.indexOf('./api/') === -1

Categories

Resources