How to exclude core-js using useBuiltIns: "usage" - javascript

Using babel 7.5.5, core-js 3.1.4 and webpack 4.38.0, how can I exclude core-js from transpiling?
I do not want to exclude node_modules altogether since I have libs that need transpiling
If I use exclude: /node_modules\/(core-js)/, a core-js module throws
TypeError: $ is not a function
This leaves me with two other options.
Use includes instead, include my src directory and every dependency that needs transpiling one by one
Use useBuiltIns: entry instead of usage, since in this case exclude: /node_modules/\(core-js)/ works, and import core.js at the top of main.js
Both of these options don't really seem like good solutions to me since usage is "no longer experimental" since 7.4.
Is there any way to make it work using usage? Is it a bug in either babel-loader or babel? Or is my configuration at fault?
This is my Webpack config:
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production',
entry: {
main: ['./src/main'],
},
output: {
path: path.resolve(__dirname, './build/'),
publicPath: '/build/'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules\/(core-js)/,
use: {
loader: 'babel-loader'
},
},
{
test: require.resolve('jquery'),
use: [
{
loader: 'expose-loader',
options: 'jQuery'
},
{
loader: 'expose-loader',
options: '$'
}
]
}
]
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
})
],
};
This is my babel config:
module.exports = function (api) {
api.cache(true);
return {
presets: [
[
'#babel/preset-env',
{
corejs: {
version: 3,
},
useBuiltIns: 'usage',
}
]
],
};
};
You can reproduce the error with the following repository: https://github.com/tomm1996/usebuiltins-exclude-test

You need to exclude both core-js and webpack/buildin from the Babel transpilation.
You can use the folling exclude Regexes:
exclude : [
/\bcore-js\b/,
/\bwebpack\/buildin\b/
]
Here is also a complete babel-loader configuration with some useful comments:
{
module : {
rules : [{
test : /\.js$/,
// Some module should not be transpiled by Babel
// See https://github.com/zloirock/core-js/issues/743#issuecomment-572074215
exclude : [
/\bcore-js\b/,
/\bwebpack\/buildin\b/
],
loader : "babel-loader",
options : {
babelrc : false,
// Fixes "TypeError: __webpack_require__(...) is not a function"
// https://github.com/webpack/webpack/issues/9379#issuecomment-509628205
// https://babeljs.io/docs/en/options#sourcetype
sourceType : "unambiguous",
presets : [
["#babel/preset-env", {
// Webpack supports ES Modules out of the box and therefore doesn’t require
// import/export to be transpiled resulting in smaller builds, and better tree
// shaking. See https://webpack.js.org/guides/tree-shaking/#conclusion
modules : false,
// Adds specific imports for polyfills when they are used in each file.
// Take advantage of the fact that a bundler will load the polyfill only once.
useBuiltIns : "usage",
corejs : {
version : "3",
proposals : true
}
}]
]
}
}
}
}
See https://github.com/zloirock/core-js/issues/743#issuecomment-572074215
Edit: Also if you try to use #babel/plugin-transform-runtime:
plugins : [
// Require the Babel runtime as a separate module to avoid the duplication
// https://webpack.js.org/loaders/babel-loader/#babel-is-injecting-helpers-into-each-file-and-bloating-my-code
["#babel/plugin-transform-runtime", {
// Requires #babel/runtime-corejs3
// https://babeljs.io/blog/2019/03/19/7.4.0#migration-from-core-js-2
corejs : { version: 3, proposals: true }
}],
}
You may run into a similar error:
Uncaught TypeError: _typeof2 is not a function
at _typeof (typeof.js:8)
at eval (sockjs.js:123)
at Object.eval (sockjs.js:131)
at eval (sockjs.js:6565)
at Object../node_modules/sockjs-client/dist/sockjs.js (main.js:13790)
at __webpack_require__ (main.js:70)
at eval (webpack://PUBLIC_ENGINE/(:8000/webpack)-dev-server/client/clients/SockJSClient.js?:110:14)
at Object../node_modules/webpack-dev-server/client/clients/SockJSClient.js (main.js:13874)
at __webpack_require__ (main.js:70)
at eval (webpack://PUBLIC_ENGINE/(:8000/webpack)-dev-server/client/socket.js?:56:41)
This can be solved by excluding #babel/runtime-corejs3 from the transpilation:
exclude : [
/\bcore-js\b/,
/\bwebpack\/buildin\b/,
/#babel\/runtime-corejs3/
]

Related

How to execute karma index.html file before all others?

I have the following karma config file (relevant properties):
files: [
{ pattern: './src/*.html', watched: true, served: true, included: false },
// polyfill for es6 Promise
'node_modules/es6-promise/dist/es6-promise.auto.js',
// polyfill for fetch.js
'node_modules/whatwg-fetch/fetch.js',
'./src/**/*.ts'
],
preprocessors: {
'**/*.html': ['html2js'],
'**/*.ts': 'karma-typescript',
'karma-babel-preprocessor': ['babel']
},
I'm using an ES6 Module project (no React, Angular2+ setup) and trying to set up my tests to run properly.
The main problem is that in my .ts file (not spec.ts --> file aimed for testing only) I have a doccument.getElementById('').someAttribute which breaks at test run time because it's null. The reason this happens is because index.html hasn't been set up yet by karma.
How do I solve the problem of index.html first being built and then all other .ts files...
Error after running npm test: *
"message": "Uncaught TypeError: Cannot set property 'innerHTML' of
null\nat
Have you tried instead of 'karma-babel-preprocessor' and 'karma-typescript' to use 'webpack' with transpilation either Babel or Typescript?
Here is https://www.npmjs.com/package/awesome-typescript-loader that can be used for TypeScript handling with webpack.
There might be kind of conflict also of using both Babel and Typescript because Typescript can transpile without babel but it is something that you can handled in webpack config. Here is how 'karma.conf' might look like with Babel:
const webpack = require('webpack');
module.exports = function (config) {
var configuration = {
browsers: ['Chrome'],
files: [
{ pattern: 'test/**/*.js', watched: true },
],
frameworks: ['jasmine'],
preprocessors: {
'test/**/*.js': ['webpack'],
},
webpack: {
module: {
loaders: [
{ test: /\.js/, exclude: /node_modules/, loader: 'babel-loader' }
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('test')
}
})
],
watch: true
},
webpackServer: {
noInfo: true
}
};
config.set(configuration);
};

How to import jquery in webpack

I have a problem with jquery when i using it on webpack.
My code:
const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const CompressionPlugin = require("compression-webpack-plugin");
module.exports = {
entry: {
vendor: [
'./src/main/webapp/js/vendor/jquery-3.3.1.min.js',
// './src/main/webapp/js/vendor/fs.js',
'./src/main/webapp/js/vendor/google-adsense.js',
'./src/main/webapp/js/vendor/jquery.menu-aim.min.js',
'./src/main/webapp/js/vendor/jquery.touchSwipe.min.js',
],
app: './src/main/assets/js/desktop/app.js',
mobile: './src/main/assets/js/mobile/app.js',
touch: './src/main/assets/js/touch/app.js',
},
module: {
rules: [{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: require.resolve('jquery'),
loader: 'expose-loader?jQuery!expose-loader?$'
}
],
},
plugins: [
// new CleanWebpackPlugin(['src/main/webapp/assets']),
new webpack.optimize.CommonsChunkPlugin({
name: 'common' // Specify the common bundle's name.
}),
new UglifyJsPlugin({
test: /\.js$/,
sourceMap: process.env.NODE_ENV === "development"
}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
],
output: {
filename: '[name].js',
path: path.resolve(__dirname, './src/main/webapp/js')
}
};
When above code compiles , console throws this error
vendor.js:1 Uncaught ReferenceError: webpackJsonp is not defined
at vendor.js:1
And when i try to use this
externals: {
jquery: 'jQuery'
}
It throws
vendor.js:1 Uncaught ReferenceError: jQuery is not defined
at Object.231 (vendor.js:1)
at o (common.js:1)
at Object.228 (vendor.js:1)
at o (common.js:1)
at window.webpackJsonp (common.js:1)
at vendor.js:1
And i using jquery in my core js file import $ from 'jquery'.
What did i do wrong ? any help ? Thank you.
So there are few themes in your webpack.config.js, some of which conflict. Just going to list them so I can better understand what I think you are trying to achieve.
Theme 1
You have an entry called vendor that is clearly referencing a minified jQuery library you have presumably downloaded and placed in the directory specified.
Theme 2
You also have an expose-loader that is essential exposing the jquery library from its node_modules probably listed in the dependencies of your package.json.
This makes the jquery in the node_modules available as $ and jQuery in the global scope of the page where your bundle is included.
Theme 3
You also have included the ProvidePlugin with configuration for jQuery.
The ProvidePlugin is supposed to inject dependencies into the scope of your module code, meaning you do not need to have import $ from 'jquery' instead $ and jQuery will already be available in all of your modules.
Conclusion
From what I have gathered I think you're trying to bundle jQuery from the static file at ./src/main/webapp/js/vendor/jquery-3.3.1.min.js in a vendor bundle.
You are then trying to expose the libraries in the vendor bundle to the global scope (jQuery).
Then also have your application code able to import jQuery from what is made available by the vendor bundle in the global scope.
Answer
So if that is what you are doing you need to do the following things.
Firstly, check in your package.json files dependencies for jquery. If its there you want to remove it, there's no need for it if you're going to use your jquery-3.3.1.min.js file instead to provide jQuery to your application.
Secondly, change your test of the expose-loader to trigger when it sees your jquery-3.3.1.min.js file in your entries, not resolve it from the jquery dependency from your node_modules.
This regex pattern should do the trick.
{
test: /jquery.+\.js$/,
use: [{
loader: 'expose-loader',
options: 'jQuery'
},{
loader: 'expose-loader',
options: '$'
}]
}
Thirdly, remove the ProvidePlugin if you're going to import the library explicitly with import $ from 'jquery' you do not need it.
Lastly, you need to tell webpack when it sees an import for jquery it can resolve this from window.jQuery in the global scope. You can do this with the externals configuration you already referenced.
externals: {
jquery: 'jQuery'
}
With all these changes you should end up with a webpack.config.js file that looks like this.
const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const CompressionPlugin = require("compression-webpack-plugin");
module.exports = {
entry: {
vendor: [
'./src/main/webapp/js/vendor/jquery-3.3.1.min.js',
// './src/main/webapp/js/vendor/fs.js',
'./src/main/webapp/js/vendor/google-adsense.js',
'./src/main/webapp/js/vendor/jquery.menu-aim.min.js',
'./src/main/webapp/js/vendor/jquery.touchSwipe.min.js',
],
app: './src/main/assets/js/desktop/app.js',
mobile: './src/main/assets/js/mobile/app.js',
touch: './src/main/assets/js/touch/app.js',
},
module: {
rules: [{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /jquery.+\.js$/,
use: [{
loader: 'expose-loader',
options: 'jQuery'
},{
loader: 'expose-loader',
options: '$'
}]
}
],
},
plugins: [
// new CleanWebpackPlugin(['src/main/webapp/assets']),
new webpack.optimize.CommonsChunkPlugin({
name: 'common' // Specify the common bundle's name.
}),
new UglifyJsPlugin({
test: /\.js$/,
sourceMap: process.env.NODE_ENV === "development"
})
],
output: {
filename: '[name].js',
path: path.resolve(__dirname, './src/main/webapp/js')
},
externals: {
jquery: 'jQuery'
}
};
I hope that does not just give you the answer but enough explanation as to where you were going wrong.

ERROR from UglifyJs: SyntaxError: Unexpected token: operator (>)

I'm getting an error when trying to run my webpack for production.
ERROR in js/main.21dbce548a76ffc14cfb.js from UglifyJs
SyntaxError: Unexpected token: operator (>) [./~/tmi.js/lib/utils.js:3,0][js/main.21dbce548a76ffc14cfb.js:3529,20]
utils.js:3,0 (which is the same as in my minified js) is:
// Return the second value if the first value is undefined..
get: (obj1, obj2) => { return typeof obj1 === "undefined" ? obj2 : obj1; },
So I assume from that the error is thrown because it's reading ES6 but it doesn't understand ES6? (The arrow function)
I don't see what's going wrong here, this is my webpack.config.js
// changed some loader syntax after reading
// https://webpack.js.org/how-to/upgrade-from-webpack-1/
const path = require(`path`);
const webpack = require(`webpack`);
const {UglifyJsPlugin} = webpack.optimize;
const CopyWebpackPlugin = require(`copy-webpack-plugin`);
const ExtractTextWebpackPlugin = require(`extract-text-webpack-plugin`);
const configHtmls = require(`webpack-config-htmls`)();
const extractCSS = new ExtractTextWebpackPlugin(`css/style.css`);
// change for production build on different server path
const publicPath = `/`;
// hard copy assets folder for:
// - srcset images (not loaded through html-loader )
// - json files (through fetch)
// - fonts via WebFontLoader
const copy = new CopyWebpackPlugin([{
from: `./src/assets`,
to: `assets`
}], {
ignore: [ `.DS_Store` ]
});
const config = {
entry: [
`./src/css/style.css`,
`./src/js/script.js`
],
resolve: {
// import files without extension import ... from './Test'
extensions: [`.js`, `.jsx`, `.css`]
},
output: {
path: path.join(__dirname, `server`, `public`),
filename: `js/[name].[hash].js`,
publicPath
},
devtool: `sourcemap`,
module: {
rules: [
{
test: /\.css$/,
loader: extractCSS.extract([
{
loader: `css`,
options: {
importLoaders: 1
}
},
{
loader: `postcss`
}
])
},
{
test: /\.html$/,
loader: `html`,
options: {
attrs: [
`audio:src`,
`img:src`,
`video:src`,
`source:srcset`
] // read src from video, img & audio tag
}
},
{
test: /\.(jsx?)$/,
exclude: /node_modules/,
use: [
{
loader: `babel`
},
{
loader: `eslint`,
options: {
fix: true
}
}
]
},
{
test: /\.(svg|png|jpe?g|gif|webp)$/,
loader: `url`,
options: {
limit: 1000, // inline if < 1 kb
context: `./src`,
name: `[path][name].[ext]`
}
},
{
test: /\.(mp3|mp4)$/,
loader: `file`,
options: {
context: `./src`,
name: `[path][name].[ext]`
}
}
]
},
plugins: [
extractCSS,
copy
]
};
if(process.env.NODE_ENV === `production`){
//image optimizing
config.module.rules.push({
test: /\.(svg|png|jpe?g|gif)$/,
loader: `image-webpack`,
enforce: `pre`
});
config.plugins = [
...config.plugins,
new UglifyJsPlugin({
sourceMap: true, // false returns errors.. -p + plugin conflict
comments: false
})
];
}
config.plugins = [...config.plugins, ...configHtmls.plugins];
module.exports = config;
OP's error is from UglifyJs, as is solved in the accepted answer, some people to this page may get the error from babel, in which case, fix it with: add "presets": ["es2015"] either to the options.presets section of babel-loader, or to .babelrc.
UglifyJs2 has a Harmony branch which accepts ES6 syntax to be minified. At this moment, you need to create a fork of webpack and point webpack to that fork.
I recently answered a couple of similar questions. Please have a look at #38387544 or #39064441 for detailed instructions.
In my case I was using webpack version 1.14
I got help from git ref
steps:
install yarn add uglifyes-webpack-plugin (and removed yarn remove uglifyjs-webpack-plugin)
then install yarn add uglify-js-es6
In webpack.config.js file change new webpack.optimize.UglifyJsPlugin to
new UglifyJsPlugin
then I was able to build. Thanks

Use fullcalendar with webpack

I use npm, webpack and FullCalendar, but I get the following error in the browser console when using fullcalendar:
main.js:37556 Uncaught TypeError: (0 , _jquery2.default)(...).fullCalendar is not a function
How do I fix this?
I use FullCalendar 3.0.0-beta and jquery 3.1.0. My code is below.
index.js:
import $ from 'jquery'
import jQueryUI from 'jquery-ui'
import moment from 'moment'
import fullCalendar from 'fullcalendar'
$('#timetable').fullCalendar({
editable: true,
firstDay: 1,
droppable: true,
})
webpack.config.js:
var path = require("path")
var webpack = require("webpack")
var BundleTracker = require("webpack-bundle-tracker")
module.exports = {
context: __dirname,
entry: [
'fullcalendar',
'./static/index',
],
output: {
path: path.resolve('./static/bundles/'),
filename: "[name].js",
},
plugins: [
new BundleTracker({filename: './webpack-stats.json'}),
],
resolve: {
modulesDirectories: ['node_modules'],
extensions: ['', '.js'],
},
module: {
loaders:[
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel', query: { presets: ['es2015'] } }
]
}
}
I know I am somewhat late to the party here, but I thought I'd answer anyway in case somebody hits this up on Google.
Whenever I run into a jQuery Plugin with Webpack (which FullCalendar is), I need to make sure that jQuery itself is exposed to the global namespace before the plugin will work through require/import.
My webpack.config.js:
var webpack = require("webpack")
var path = require("path")
var ExtractTextPlugin = require("extract-text-webpack-plugin")
var HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
entry: {
app: "./index.js",
vendor: [
"jquery",
"moment",
"fullcalendar"
]
},
output: {
path: path.join(__dirname, '../../public'),
publicPath: '/',
filename: "scripts/app.[chunkhash].js"
},
module: {
loaders: [
{ test: /\.css$/, loader: ExtractTextPlugin.extract("style", ["css"]) },
{ test: require.resolve('jquery'), loader: 'expose?$!expose?jQuery' },
{ test: require.resolve('moment'), loader: 'expose?moment' }
]
},
resolve: {
alias: {
jquery: path.resolve(path.join(__dirname, '../..', 'node_modules', 'jquery')),
fullcalendar: 'fullcalendar/dist/fullcalendar'
}
},
plugins: [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.CommonsChunkPlugin({ names: ["vendor"], filename: "scripts/[name].[chunkhash].js" }),
new ExtractTextPlugin("styles/[name].[chunkhash].css"),
new HtmlWebpackPlugin({
template: "index.html.handlebars"
}),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
]
};
The relevant part is where jquery and moment are forced to be in the global namespace via the loader: 'expose?$!expose?jQuery' syntax.
Second, because fullcalendar is packaged in a way that the require can't automatically pick it up, I setup an alias so that I can have a clean package name. This is the alias: { fullcalendar: 'fullcalendar/dist/fullcalendar' } bit.
These two let me load fullcalendar via require/import and use it as I normally would.
The styles also need to be loaded. For this one I have not created aliases yet, so I just did a relative path to the css file:
#import "../../../node_modules/fullcalendar/dist/fullcalendar.css";
You can replace fullcalendar.js with fullcalendar.min.js to avoid recompressing, but for my use case because I was bundling all the vendor JS files together, I thought I would get better compression if I had more files concatenated. (Ditto for CSS fullcalendar.css with fullcalendar.min.css)
Disclaimer: I don't know if this is the "correct" way of doing this, but I know it took me a fair bit of trial and error with webpack to get jQuery plug ins like FullCalendar and Select2 to work, and this shell and method did make it easy.
For reference, links to the relevant files in a public repo where I use this pattern:
webpack.config.js: https://github.com/thegrandpoobah/mftk-back-office/blob/e531de0a94130d6e9634ba5ab547a3e4d41c5c5f/app/src/public/webpack.config.js
style scss: https://github.com/thegrandpoobah/mftk-back-office/blob/e531de0a94130d6e9634ba5ab547a3e4d41c5c5f/app/src/public/styles/main.scss
module where I use fullcalendar: https://github.com/thegrandpoobah/mftk-back-office/blob/e531de0a94130d6e9634ba5ab547a3e4d41c5c5f/app/src/public/students/index.js#L277
This is a step by step guide based on the data from above and other sources. First make sure you have moment.js installed:
npm install moment
Then make sure you have the fullcalendar version 3.10.2, which is the latest in version 3 which is optimized not bundling jQuery nor moment.js , and although it's not the latest version, it uses the old syntax, which won't break compatibility with legacy code:
npm install fullcalendar#3.10.2
Then install script-loader
npm install --save-dev script-loader
If you are using Laravel, then in resources/js/bootstrap.js add the following lines below bootstrap and jquery (note the use of script-lader!) :
window.moment = require('moment');
require('script-loader!fullcalendar/dist/fullcalendar');
require('script-loader!fullcalendar/dist/locale-all');
Then add the css style in resources/sass/app.scss:
#import '~fullcalendar/dist/fullcalendar.min.css';
Finally do:
npm run dev
Or, for production:
npm run prod
That's all
I think I found an even easier solution.
We're using fullcalendar and scheduler. We're converting from Rails sprockets to webpack. Adding fullcalendar to a lazyloaded chunk with webpack caused it to introduce two additional moments and jquerys (yep two) which, of course, didn't pick up our configuration changes as those where done on the original version in our chunked vendor file.
Ideally we just wanted fullcalendar included with no module processing (it does absolutely nothing and is totally unnecessary). Fortunately you can do this with webpack's script-loader.
require('script-loader!fullcalendar/dist/fullcalendar.js')
And you're done. Same with the scheduler. It loads it in isolation and unprocessed which is exactly what you want with a jquery plugin.
With webpack 5, below code solves the issue:
module: {
rules: [
{
test: require.resolve('jquery'),
loader: 'expose-loader',
options: {
exposes: ["$", "jQuery"]
}
},
{
test: require.resolve('moment'),
loader: 'expose-loader',
options: {
exposes: "moment"
}
},
{
test: require.resolve('fullcalendar'),
use: [
{
loader: 'script-loader',
options: 'fullcalendar/dist/fullcalendar.js'
}
]
},
{
test: require.resolve('fullcalendar-scheduler'),
use: [
{
loader: 'script-loader',
options: 'fullcalendar/dist/fullcalendar-scheduler.js'
}
]
},
]
},
I used fullCalendar for example:
$("#fullcalendar-activities").fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
events: events,
defaultView: 'month'
});

Make webpack's library output compatible with babel6

Babel's 6th version changes the functioning of export default and in particular its relation with commonjs require.
To summarise, while until babel5, require('module') where giving the default export of the module, it now always returns the module object containing all of the exports of the module.
If one only wants the default, he/she must use require('module').default.
As explained here, there is very good reasons behind this and the aim of this question is not to break or hack this behaviour.
However, if one is building a library, he/she usually does not want to distribute a module but the export value of his library (e.g. a function, whatever module system is used internally).
This is well dealt with by webpack and the output.library configuration when using commonjs or AMD. Because prior babel's versions allowed the default export to be required with commonjs, babel was also compatible with this mechanism. However it is not the case anymore: the library now always provides an es6 module object.
Here is an example.
src/main.js
export default "my lib content";
webpack.config.js
var path = require("path");
var webpack = require("webpack");
module.exports = {
entry: {
lib: [ path.resolve(__dirname, "src/main.js") ],
},
output: {
path: path.join(__dirname, "dist"),
filename: "mylib-build.js",
library: 'myLib'
},
module: {
loaders: [
{
test: /\.js$/,
loader: "babel",
include: path.join(__dirname, "src"),
query: { presets: ['es2015'] }
}
]
}
};
test.html
<html>
<head></head>
<body>
<script src="dist/mylib-build.js"></script>
<!-- `myLib` will be attached to `window` -->
<script>
console.log(JSON.stringify(myLib)); // { default: "my lib content" }
</script>
</body>
</html>
This is a very simple example but I obviously want the export of mylib to be the string "my lib content" instead of { default: "my lib content" }.
One solution could be to create an export source file in commonjs to perform the transformation:
module.exports = require('./main').default;
However I find this solution quite poor. One should be able to solve it at the compilation level, without changing the source code.
Any idea?
Was just going at this my self. Whether one like to call it a workaround or solution, there seem to be a Babel plugin that "solve it".
Using the plugin babel-plugin-add-module-exports as referenced in https://stackoverflow.com/a/34778391/1592572
Example config
var webpackOptions = {
entry: {
Lib1: './src/Lib1.js',
Lib2: './src/Lib2.js'
},
output: {
filename: "Master.[name].js",
library: ["Master","[name]"],
libraryTarget: "var"
},
module: {
loaders: [
{
loader: 'babel',
query: {
presets: ['es2015'],
plugins: ["add-module-exports"]
}
}
]
}
};
This yields Master.Lib1 to be lib1 instead of Master.Lib1.default.
Webpack 2 now supports es6 modules which partially solves this issue. Migrating from webpack 1 to webpack 2 is relatively painless. One just needs to remember to disable babel's es6 module to commonjs conversion to make this work:
.babelrc
{
"presets": [
["es2015", {"modules": false}]
]
}
However, unfortunately, it does not work properly with export default (but an issue is opened, hopefully a solution will be released eventually).
EDIT
Good news! Webpack 3 supports the output.libraryExport option that can be used to directly expose the default export:
var path = require("path");
var webpack = require("webpack");
module.exports = {
entry: {
lib: [ path.resolve(__dirname, "src/main.js") ],
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "mylib-build.js",
library: "myLib",
// Expose the default export.
libraryExport: "default"
},
module: {
loaders: [
{
test: /\.js$/,
loader: "babel",
include: path.resolve(__dirname, "src")
}
]
}
};
You can use this solution (this is more like workaround, but it allow you to keep your sources from change):
There is a loader called callback-loader. It allow you to change your sources in a build time by calling a callback and put a result instead of it. In other words you can turn all you require('module') into a require('module').default automatically in a build time.
Here is your config for it:
var webpackConfig = {
module: {
loaders: [
{ test: /\.js$/, exclude: /node_modules/, loader: 'callback' },
...
]
},
...
callbackLoader: {
require: function() {
return 'require("' + Array.prototype.join.call(arguments, ',') + '").default';
}
}
};

Categories

Resources