Unable to include 3-d party component in React - javascript

I'm trying to include 3-d party component as follows:
app.js
/** #jsx React.DOM */
var React = require('react'),
ReactDOM = require('react-dom');
Isvg = require('react-inlinesvg');
ReactDOM.render(
<Isvg src="images/mobile.svg" />,
document.getElementById('mobile')
);
package.json:
...
"browser": {
"react": "./node_modules/react/dist/react.js",
"react-dom": "./node_modules/react-dom/dist/react-dom.js",
"react-inlinesvg": "./bower_components/react-inlinesvg/standalone/react-inlinesvg.js",
"react-lazyload": "./node_modules/react-lazy-load/dist/LazyLoad.js"
},
"browserify": {
"transform": [
["reactify", {"es6": true}]
]
}
and finally gulp task configuration:
var gulp = require('gulp'),
config = require('../config')(),
utils = require('../utils'),
plugins = require('gulp-load-plugins')({lazy: true}),
browserify = require('browserify'),
source = require('vinyl-source-stream'),
reactify = require('reactify'),
watchify = require('watchify');
gulp.task('make-js', function() {
var options = {
debug: true,
entries: config.js,
transform: [reactify],
cache: {}, packageCache: {}, fullPaths: true
},
bundler = watchify(browserify(options));
bundler.on('update', rebundle);
function rebundle() {
utils.log('start bundling...');
bundler
.bundle()
.on('error', utils.handleErrors)
.pipe(source('bundle.js'))
.pipe(gulp.dest(config.tmp));
utils.log('finished bundling...');
}
return rebundle();
});
This creates bundle.js file without any problems however the 3-d party inlinesvg component does not work and produces the following error in the browser javascript console:
Uncaught TypeError: Cannot read property 'PropTypes' of undefined
The error is caused by the following code in react-inlinesvg.js
Line 566
PropTypes = React.PropTypes;
I'm pretty sure I've missed something important in the browserify configuration but cannot figure out what I did wrong exactly.
Thanks for your help.

It seems to be an issue with that 3-d party component. I'm newbie in react so in order to exclude my configuration errors I used 100% working boilerplate. But the issue remained. The investigation revealed the module itself does not import React in a proper way.
My original question could be actually split into 2 questions (how to include that module and how to load SVG files inline so let me answer the second part of my question).
I did not find any working modules which could load svg without any 3-d party modules like jquery or creating my own bicycle.
I came up with the well-known SVGInjector javascript module. It is a vanilla js module but has the necessary browserify support. I wrapped it into react component without problems. Here is the code:
class svg extends React.Component {
componentDidMount(){
return SVGInjector([ReactDOM.findDOMNode(this)]);
}
constructor(props) {
super(props);
}
render() {
return React.DOM.img({
className: this.props.className,
'data-src': this.props.path,
'data-fallback': this.props.fallbackPath});
}
}

Related

Yarn Workspaces, workspace does not emit errors or warnings

I have followed the following post in order to create a monorepo using yarn workspaces and craco.
It works really well except one thing: the errors/warnings of the common (components )library are not emitted to the console.
The structure is very simple:
monorepo
|-packages
|-components
|-fe
Fe is the main webApp that uses the components library.
The FE emits all warnings correctly, components does not.
How to make the shared component emit warnings/errors?
Updated:
Steps to reproduce in this repo:
https://github.com/sofoklisM/my-monorepo.git
What you need to change is the context option of the underlying ESLint Webpack plugin that is used by Create React App.
In this case I changed the context of ESLint to the root of the monorepo (yarn workspace root).
Here is an updated craco.config.js that should do the trick:
// craco.config.js
const path = require("path");
const { getLoader, loaderByName } = require("#craco/craco");
const { getPlugin, pluginByName } = require("#craco/craco/lib/webpack-plugins")
const absolutePath = path.join(__dirname, "../components");
module.exports = {
webpack: {
alias: {},
plugins: [],
configure: (webpackConfig, { env, paths }) => {
const { isFound, match } = getLoader(
webpackConfig,
loaderByName("babel-loader")
);
if (isFound) {
const include = Array.isArray(match.loader.include)
? match.loader.include
: [match.loader.include];
match.loader.include = include.concat([absolutePath]);
}
// Change context of ESLint Webpack Plugin
const { match: eslintPlugin } = getPlugin(webpackConfig, pluginByName("ESLintWebpackPlugin"));
eslintPlugin.options['context'] = path.join(__dirname, "../..");
return webpackConfig;
}
}
};
I've also made an updated fork of your reproduction repo here: https://github.com/ofhouse/stackoverflow-65447779

Specify code to run before any Jest setup happens

The tl;dr is:
1) How can I have Jest use the native require function to load all modules in my tests anywhere.
2) Where / how would I go about modifying (ie replacing with the esm loader) https://github.com/standard-things/esm the require function in one place, before any tests run, so all tests will use the modified require.
I'd like to use the esm-loader with my Jest test files. In order to do so, I need to patch the require function globally, before any test code runs, with something like
require = require("#std/esm")(module, { esm: "js", cjs: true });
How do I tell Jest to execute that code before anything else is touched or requested?
I tried pointing both setupTestFrameworkScriptFile and an setupFiles array entry to a file with that in it, but neither worked (though I did confirm that both ran).
Alternatively, I'm firing off these tests with an npm script
"scripts": {
"test": "jest"
}
Is there some CLI magic whereby I can just load a module and then run jest?
Edit - the testEnvironment and resolver options make me wonder if this is ever even using the actual Node require function to load modules, or instead using its own module loader. If so I wonder if this is even possible.
So this one was a bit tough to get working. The solution is quite simple but it took me a while to get it working. The problem is that whenever you use any module in jest
Setup Files
Setup Framework Files
Test Files
Module files
They are all loaded in below way
({"Object.":function(module,exports,require,__dirname,__filename,global,jest){/*Module code inside*/
}});
If you have a look at node_modules/jest-runtime/build/index.js:495:510
const dirname = (_path || _load_path()).default.dirname(filename);
localModule.children = [];
localModule.parent = mockParentModule;
localModule.paths = this._resolver.getModulePaths(dirname);
localModule.require = this._createRequireImplementation(filename, options);
const transformedFile = this._scriptTransformer.transform(
filename,
{
collectCoverage: this._coverageOptions.collectCoverage,
collectCoverageFrom: this._coverageOptions.collectCoverageFrom,
collectCoverageOnlyFrom: this._coverageOptions.collectCoverageOnlyFrom,
isInternalModule,
mapCoverage: this._coverageOptions.mapCoverage },
this._cacheFS[filename]);
this._createRequireImplementation(filename, options); gives every module a custom require object. So you as such don't get the native require function at all, anywhere. Once jest has started every module loaded from then on will have jest's custom require function.
When we load a module, the requireModule methods from the jest-runtime gets called. Below is an excerpt from the same
moduleRegistry[modulePath] = localModule;
if ((_path || _load_path()).default.extname(modulePath) === '.json') {
localModule.exports = this._environment.global.JSON.parse(
(0, (_stripBom || _load_stripBom()).default)((_gracefulFs || _load_gracefulFs()).default.readFileSync(modulePath, 'utf8')));
} else if ((_path || _load_path()).default.extname(modulePath) === '.node') {
// $FlowFixMe
localModule.exports = require(modulePath);
} else {
this._execModule(localModule, options);
}
As you can see if the extension of the file is .node it loads the module directly, else it calls the _execModule. This function is the same code that I posted earlier which does the code transformation
const isInternalModule = !!(options && options.isInternalModule);
const filename = localModule.filename;
const lastExecutingModulePath = this._currentlyExecutingModulePath;
this._currentlyExecutingModulePath = filename;
const origCurrExecutingManualMock = this._isCurrentlyExecutingManualMock;
this._isCurrentlyExecutingManualMock = filename;
const dirname = (_path || _load_path()).default.dirname(filename);
localModule.children = [];
localModule.parent = mockParentModule;
localModule.paths = this._resolver.getModulePaths(dirname);
localModule.require = this._createRequireImplementation(filename, options);
Now when we want to modify require function for our test, we need _execModule to export our code directly. So the code should be similar to loading of a .node modules
} else if ((_path || _load_path()).default.extname(modulePath) === '.mjs') {
// $FlowFixMe
require = require("#std/esm")(localModule);
localModule.exports = require(modulePath);
} else {
But doing that would mean patching the code, which we want to avoid. So what we do instead is avoid using the jest command directly, and create our own jestload.js and running that. The code for loading jest is simple
#!/usr/bin/env node
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
cli = require('jest/bin/jest');
Now we want to modify the _execModule before the cli loads. So we add below code
const jestRuntime = require("jest-runtime");
oldexecModule = jestRuntime.prototype._execModule;
jestRuntime.prototype._execModule = function (localModule, options) {
if (localModule.id.indexOf(".mjs") > 0) {
localModule.exports = require("#std/esm")(localModule)(localModule.id);
return localModule;
}
return oldexecModule.apply(this, [localModule, options]);
};
cli = require('jest/bin/jest');
Now time for a test
//__test__/sum.test.js
sum = require('../sum.mjs').sum;
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
test('adds 2 + 3 to equal 5', () => {
expect(sum(3, 2)).toBe(5);
});
And a sum.mjs file
export function sum (x, y) { return x + y }
Now we run the test
The solution is available on below repo
https://github.com/tarunlalwani/jest-overriding-require-function-stackoverflow
You can clone and test the solution by running npm test.
setupFiles worked for me. Add this in package.json:
"jest": {
"setupFiles": ["./my_file.js"]
},
https://jestjs.io/docs/en/configuration.html#setupfiles-array
I tried using node -r #std/esm run.js where run.js is just a script that calls jest, but it does not work and crashes here : https://github.com/facebook/jest/blob/master/packages/jest-runtime/src/script_transformer.js#L305.
From what I understand from this line means that it is not possible because jest compiles the module using the native vm module. The above lines (290):
if (willTransform) {
const transformedSource = this.transformSource(
filename,
content,
instrument,
!!(options && options.mapCoverage));
wrappedCode = wrap(transformedSource.code);
sourceMapPath = transformedSource.sourceMapPath;
} else {
is the code called when you are specifying transforms in your jest config.
Conclusion : until esm are supported ( and they will be under the .mjs extension ) you cannot import es modules in jest without specifying a transform. You could try to monkey patch vm but I would really advise against this option.
Specifying a jest transform is really not that hard, and for es modules it's really as simple as using babel-jest with the right babel config :
Below a package.json with minimal settings
{
"dependencies": {
"babel-jest": "^21.2.0",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
"jest": "^21.2.1"
},
"jest": {
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.js?(x)",
"<rootDir>/src/**/?(*.)(spec|test).js?(x)"
],
"transform": {
"^.+\\.(js|jsx)$": "<rootDir>/node_modules/babel-jest"
},
"testEnvironment": "node",
"testURL": "http://localhost",
"moduleFileExtensions": [
"js",
"json"
]
},
"babel": {
"plugins": ["babel-plugin-transform-es2015-modules-commonjs"]
}
}

How can I add Font Awesome to my Aurelia project using npm?

I have been following the Contact Manager tutorial and would like to add Font Awesome to the project. Here's what I have done so far:
npm install Font-Awesome --save
Added the following to aurelia.jsonunder the dependencies array of the vendor-bundle.js:
...
{
"name": "font-awesome",
"path": "../node_modules/font-awesome",
"resources": [
"css/font-awesome.min.css"
]
},
...
But when running au run --watch I get the error:
error
C:\Users\node_modules\font-awesome.js
Why is it looking for the .js file?
Don't add font-awesome resources to aurelia.json - you'd need font files too, which Aurelia don't process. Instead, take the following steps.
First, if you added anything for font-awesome already to your aurelia.json file, remove it again.
Add new file prepare-font-awesome.js in folder \aurelia_project\tasks and insert the below code. It copies font-awesome resource files to output folder (as configured aurelia.json config file; e.g. scripts):
import gulp from 'gulp';
import merge from 'merge-stream';
import changedInPlace from 'gulp-changed-in-place';
import project from '../aurelia.json';
export default function prepareFontAwesome() {
const source = 'node_modules/font-awesome';
const taskCss = gulp.src(`${source}/css/font-awesome.min.css`)
.pipe(changedInPlace({ firstPass: true }))
.pipe(gulp.dest(`${project.platform.output}/css`));
const taskFonts = gulp.src(`${source}/fonts/*`)
.pipe(changedInPlace({ firstPass: true }))
.pipe(gulp.dest(`${project.platform.output}/fonts`));
return merge(taskCss, taskFonts);
}
Open the build.js file in the \aurelia_project\tasks folder and insert the following two lines; this will import the new function and execute it:
import prepareFontAwesome from './prepare-font-awesome'; // Our custom task
export default gulp.series(
readProjectConfiguration,
gulp.parallel(
transpile,
processMarkup,
processCSS,
prepareFontAwesome // Our custom task
),
writeBundles
);
Finally, in the <head> section of your index.html file, just add the following line:
<link rel="stylesheet" href="scripts/css/font-awesome.min.css">
That's all; now you can use font-awesome icons in any Aurelia view modules (html files).
Note that this works for any complex third party library which requires resources which you have to manually include.
Simple default settings method
Here are the 4 simple steps I use to bring in Font-Awesome to an Aurelia project that uses the CLI.
1) npm install font-awesome --save
2) add copyFiles to build of aurelia.json
"build": {
"copyFiles": {
"node_modules/font-awesome/fonts/*": "/fonts/"
},
3) add bundling to dependencies array of aurelia.json
"dependencies": [
{
"name": "font-awesome",
"path": "../node_modules/font-awesome/css",
"main": "font-awesome.css"
},
4) include the import for the css file (mine lives in the app.html)
<require from="font-awesome.css"></require>
=========================================================================
Alternative
Specifying a custom font location
As I was serving my files from a different location I needed to be able to tweek the font location configured. As such, below are the steps involved if you need to do the same and specify where the fonts are stored. I am using .less
1, 2) As above.
3) Instead of adding to the bundling, you need to reference the font-awesome less file within your own less file (mine is called site.less) and then set the #fa-font-path to your custom location.
#import "../node_modules/font-awesome/less/font-awesome.less";
#fa-font-path: "fonts";
4) There is no 4, with this method as long as you have your own compiled equivalent site.css file referenced already (with the import) you don't need to add anything else.
Funny I was trying to get the same thing working this morning. This is all I had to do in my aurelia.json dependencies for it to work:
{
"name": "font-awesome",
"path": "../node_modules/font-awesome/",
"main": "",
"resources": [
"css/font-awesome.min.css"
]
},
Then in my html I had:
<require from="font-awesome/css/font-awesome.min.css"></require>
Not actually answering to your question of how to integrate Font Awesome in your application using NPM, but there is an alternative, clean way to get it in your application: using the CDN.
As mentioned in other answers, Aurlia currently doesn't support bundling resources other than js, css and html out-of-the-box using the CLI. There's a lot of discussion about this subject, and there are several, mostly hacky, workarounds, like some suggested here.
Rob Eisenberg says he's planning on getting it properly integrated in the Aurelia CLI, but he considers it low priority because there's a simple workaround. To quote him:
Of course there is interest in addressing this. However, it's lower priority than other things on the list for the CLI, in part because a simple link tag will fix the problem and is much easier than the work we would have to do to solve this inside the CLI.
Source: https://github.com/aurelia/cli/issues/248#issuecomment-254254995
Get your unique CDN link mailed here: http://fontawesome.io/get-started/
Include this link in the head of your index html file
Don't forget to remove everything you might have already added to try to get it working: the npm package (and its reference in your package.json), the reference in your aurelia.json file, any custom tasks you might have created, any <require> tags,...
importing css/fonts automagicly is now supported.
{
"name": "font-awesome",
"path": "../node_modules/font-awesome/css",
"main": "font-awesome.css"
}
<require from="font-awesome.css"></require>
Checkout this "Issue" https://github.com/aurelia/cli/issues/249
Happy codding
EDIT
I realized/read the comments this does not copy the font files.
Here is an updated build script (es6) that will copy any resources and add the folder to the git ignore. If you want the typescript version check here
https://github.com/aurelia/cli/issues/248#issuecomment-253837412
./aurelia_project/tasks/build.js
import gulp from 'gulp';
import transpile from './transpile';
import processMarkup from './process-markup';
import processCSS from './process-css';
import { build } from 'aurelia-cli';
import project from '../aurelia.json';
import fs from 'fs';
import readline from 'readline';
import os from 'os';
export default gulp.series(
copyAdditionalResources,
readProjectConfiguration,
gulp.parallel(
transpile,
processMarkup,
processCSS
),
writeBundles
);
function copyAdditionalResources(done){
readGitIgnore();
done();
}
function readGitIgnore() {
let lineReader = readline.createInterface({
input: fs.createReadStream('./.gitignore')
});
let gitignore = [];
lineReader.on('line', (line) => {
gitignore.push(line);
});
lineReader.on('close', (err) => {
copyFiles(gitignore);
})
}
function copyFiles(gitignore) {
let stream,
bundle = project.build.bundles.find(function (bundle) {
return bundle.name === "vendor-bundle.js";
});
// iterate over all dependencies specified in aurelia.json
for (let i = 0; i < bundle.dependencies.length; i++) {
let dependency = bundle.dependencies[i];
let collectedResources = [];
if (dependency.path && dependency.resources) {
// run over resources array of each dependency
for (let n = 0; n < dependency.resources.length; n++) {
let resource = dependency.resources[n];
let ext = resource.substr(resource.lastIndexOf('.') + 1);
// only copy resources that are not managed by aurelia-cli
if (ext !== 'js' && ext != 'css' && ext != 'html' && ext !== 'less' && ext != 'scss') {
collectedResources.push(resource);
dependency.resources.splice(n, 1);
n--;
}
}
if (collectedResources.length) {
if (gitignore.indexOf(dependency.name)< 0) {
console.log('Adding line to .gitignore:', dependency.name);
fs.appendFile('./.gitignore', os.EOL + dependency.name, (err) => { if (err) { console.log(err) } });
}
for (let m = 0; m < collectedResources.length; m++) {
let currentResource = collectedResources[m];
if (currentResource.charAt(0) != '/') {
currentResource = '/' + currentResource;
}
let path = dependency.path.replace("../", "./");
let sourceFile = path + currentResource;
let destPath = './' + dependency.name + currentResource.slice(0, currentResource.lastIndexOf('/'));
console.log('Copying resource', sourceFile, 'to', destPath);
// copy files
gulp.src(sourceFile)
.pipe(gulp.dest(destPath));
}
}
}
}
}
function readProjectConfiguration() {
return build.src(project);
}
function writeBundles() {
return build.dest();
}
I believe that bundles.dependencies section is for referencing JS libraries.
In your case, a bit of additional work will be needed. According to Aurelia CLI docs, you can create your own generators as well, which comes in handy for us.
Add some new paths to aurelia.json:
"paths": {
...
"fa": "node_modules\\font-awesome",
"faCssOutput": "src",
"faFontsOutput": "fonts"
...
}
Create a task for css bundling...
au generate task fa-css
Modified task file: aurelia_project\tasks\fa-css.js|ts
import * as gulp from 'gulp';
import * as changedInPlace from 'gulp-changed-in-place';
import * as project from '../aurelia.json';
import {build} from 'aurelia-cli';
export default function faCss() {
return gulp.src(`${project.paths.fa}\\css\\*.min.css`)
.pipe(changedInPlace({firstPass:true}))
/* this ensures that our 'require-from' path
will be simply './font-awesome.min.css' */
.pipe(gulp.dest(project.paths.faCssOutput))
.pipe(gulp.src(`${project.paths.faCssOutput}\\font-awesome.min.css`))
.pipe(build.bundle());
};
...and another for copying font files:
au generate task fa-fonts
Modified task file: aurelia_project\tasks\fa-fonts.js|ts
import * as gulp from 'gulp';
import * as project from '../aurelia.json';
export default function faFonts() {
return gulp.src(`${project.paths.fa}\\fonts\\*`)
.pipe(gulp.dest(project.paths.faFontsOutput));
}
Add these new tasks above to the build process in aurelia_project\tasks\build.js|ts:
export default gulp.series(
readProjectConfiguration,
gulp.parallel(
transpile,
processMarkup,
processCSS,
// custom tasks
faCss,
faFonts
),
writeBundles
);
After doing these steps, au build should embed font-awesome.min.css into scripts/app-bundle.js and copy necessary font files to ./fonts folder.
Last thing to do is to require font-awesome within our html.
<require from ="./font-awesome.min.css"></require>
You don't need more much this:
in aurelia.json
"dependencies": [
"jquery",
"text",
{
"name": "bootstrap",
"path": "../node_modules/bootstrap/dist/",
"main": "js/bootstrap.min",
"deps": ["jquery"],
"resources": [
"css/bootstrap.min.css"
]
},
{
"name": "font-awesome",
"path": "../node_modules/font-awesome/css",
"main": "",
"resources": [
"font-awesome.min.css"
]
}
]
}
],
"copyFiles": {
"node_modules/font-awesome/fonts/fontawesome-webfont.woff": "fonts/",
"node_modules/font-awesome/fonts/fontawesome-webfont.woff2": "fonts/",
"node_modules/font-awesome/fonts/FontAwesome.otf": "fonts/",
"node_modules/font-awesome/fonts/fontawesome-webfont.ttf": "fonts/",
"node_modules/font-awesome/fonts/fontawesome-webfont.svg": "fonts/"
}
See section Setup for copying files
i hope help you.
For those who wish to use the sass version of font-awesome
1) Install font-awesome
npm install font-awesome --save
2) Copy font-awesome's fonts to your project root directory
cp -r node_modules/font-awesome/fonts .
3) Include the font-awesome sass directory in the aurelia css processor task
# aurelia_project/tasks/process-css.js
export default function processCSS() {
return gulp.src(project.cssProcessor.source)
.pipe(sourcemaps.init())
.pipe(sass({
includePaths: [
'node_modules/font-awesome/scss'
]
}).on('error', sass.logError))
.pipe(build.bundle());
};
4) Import font-awesome in your app scss
# src/app.scss
#import 'font-awesome';
5) Require your app scss in your html
# src/app.html
<template>
<require from="./app.css"></require>
</template>

Unexpected "Uncaught TypeError: XXX is not a constructor" errors with Babel and ES6

I am giving a try to Webpack, and am giving a try to the instructions in this tutorial, give or take a few custom things.
This is simple code, really, but I'm quite puzzled about this error, and feel this is something silly that I missed.
I defined two ES6 classes, each corresponding to a Handlebars template, and my app's entrypoint is supposed to replace the placeholder HTML in the index file by their contents:
Entrypoint:
import './bloj.less'
// If we have a link, render the Button component on it
if (document.querySelectorAll('a').length) {
require.ensure([], () => {
const Button = require('./Components/Button.js');
const button = new Button('9gag.com');
button.render('a');
}, 'button');
}
// If we have a title, render the Header component on it
if (document.querySelectorAll('h1').length) {
require.ensure([], () => {
const Header = require('./Components/Header.js');
new Header().render('h1');
}, 'header');
}
Index:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1>My title</h1>
<a>Click me</a>
<script src="build/bloj.js"></script>
</body>
</html>
Button:
import $ from 'jquery';
import './Button.less';
export default class Button {
constructor(link) {
this.link = link;
}
onClick(event) {
event.preventDefault();
alert(this.link);
}
render(node) {
const text = $(node).text();
var compiled = require('./Button.hbs');
// Render our button
$(node).html(
compiled({"text": text, "link": this.link})
);
// Attach our listeners
$('.button').click(this.onClick.bind(this));
}
}
Header:
import $ from 'jquery';
import './Header.less';
export default class Header {
render(node) {
const text = $(node).text();
var compiled = require('./Header.hbs');
// Render the header
$(node).html(
compiled({"text": text})
);
}
}
Sadly, it does not work, and I get both these errors when displaying the page:
Uncaught TypeError: Header is not a constructor
Uncaught TypeError: Button is not a constructor
What could I be missing?
Here is my webpack configuration:
var path = require('path');
var webpack = require('webpack');
var CleanPlugin = require('clean-webpack-plugin');
var ExtractPlugin = require('extract-text-webpack-plugin');
var production = process.env.NODE_ENV === 'production';
var appName = 'bloj';
var entryPoint = './src/bloj.js';
var outputDir = './build/';
var publicDir = './build/';
// ************************************************************************** //
var plugins = [
//new ExtractPlugin(appName + '.css', {allChunks: true}),
new CleanPlugin(outputDir),
new webpack.optimize.CommonsChunkPlugin({
name: 'main',
children: true,
minChunks: 2
})
];
if (production) {
plugins = plugins.concat([
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.MinChunkSizePlugin({
minChunkSize: 51200 // 50ko
}),
new webpack.optimize.UglifyJsPlugin({
mangle: true,
compress: {
warnings: false // Suppress uglification warnings
}
}),
new webpack.DefinePlugin({
__SERVER__: false,
__DEVELOPMENT__: false,
__DEVTOOLS__: false,
'process.env': {
BABEL_ENV: JSON.stringify(process.env.NODE_ENV)
}
})
]);
}
module.exports = {
entry: entryPoint,
output: {
path: outputDir,
filename: appName + '.js',
chunkFilename: '[name].js',
publicPath: publicDir
},
debug: !production,
devtool: production ? false : 'eval',
module: {
loaders: [
{
test: /\.js/,
loader: "babel",
include: path.resolve(__dirname, 'src'),
query: {
presets: ['es2015']
}
},
{
test: /\.less/,
//loader: ExtractPlugin.extract('style', 'css!less')
loader: "style!css!less"
},
{
test: /\.html/,
loader: 'html'
},
{
test: /\.hbs/,
loader: "handlebars-template-loader"
}
]
},
plugins: plugins,
node: {
fs: "empty" // Avoids Handlebars error messages
}
};
What could I be missing?
Babel assigns default exports to the default property. So if you use require to import ES6 modules, you need to access the default property:
const Button = require('./Components/Button.js').default;
I realize that you already have an answer. However I had a similar issue to which I found an answer. Starting my own question and answering it seems weird.
So I'm just going to leave this here.
I had the same error as you got. However, I managed to solve it by changing my
export default {Class}
to
export default Class
I don't know why I wrapped the Class in an object but I remember having seen it somewhere so I just started using it.
So instead of the default returning a Class it returned an object like this {Class: Class}.
This is completely valid yet it will break webpack+babel.
EDIT: I've since come to know why this probably breaks babel+webpack. The export default is meant to only have 1 export. A javascript-object can contain many properties. Which means it can have more than 1 export. (See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export).
For multiple exports use: export {definition1, definition2}.
Use-case: I've used this in a situation where I've created a library which exported different types of an editor (while the underlying code was the same, the appearance of the editor changes depending on which export you use).
You can just put export var __useDefault = true; just after exporting your Class.
export default class Header {
...
}
export var __useDefault = true;
I was able to fix this by adding babel-plugin-add-module-exports to the .babelrc file
npm install babel-plugin-add-module-exports --save-dev
{
"presets": ["#babel/env"],
"plugins": ["add-module-exports"]
}
this adds
module.exports = exports.default;
to the last line when compiling the class with babel.
Although this is not the cause of your particular issue, I ran into a very similar problem when trying to rip babel out of an existing node app that was using ES6's import and export syntax, so this post is to help out anyone else struggling with this in the future.
Babel will resolve any circular dependencies between one module and another, so you can use ES6's import and export with reckless abandon. However, if you need to get rid of babel and use native node, you will need to replace any import and exports with require. This can reintroduce a latent circular reference issues that babel was taking care of in the background. If you find yourself in this situation, look for an area in your code that looks like this:
File A:
const B = require('B');
class A {
constructor() {
this.b = new B();
}
}
module.exports = A;
File B:
const A = require('A'); // this line causes the error
class B {
constructor() {
this.a = new A();
}
}
module.exports = B;
There are several different ways to resolve this issue depending on how you structured your code. The easiest way is probably to pass B a reference to A instead of creating a new instance of class A. You could also dynamically resolve the reference when loading A. There are a myriad of other alternatives, but this is a good place to get started.
It's not the problem in this particular question, but for some reasons, babel does not hoist classes in the same file.
So if you declare your class Token at the top of the file, and write later new Token(), it will run.
If you declare your class after the constructor call, you will have the xxx is not a constructor error
I had the same error message and discovered that the cause was circular import statements. That is: I had two files that imported each other, wherein one file contained an export default class that contained a method that was dependent upon an export function from the other file.
My solution was to move one of the dependencies (functions) out of the class and into a utils.js file, which was a more appropriate place for it anyway!
This is the way I am using / importing my classes:
Utils.class.js
export default class Utils {
somefunction(val) {
return val
}
}
Using Utils into my controllers:
import {default as U} from '../helpers/Utils.class';
const Utils = new U();
console.log(Utils.somefunction(123));

Webpack externals dependency

I have modular javascript application and I need to have js frameworks in one file "global-libs.js", which dependencies will be accessible for every file using webpack. Other js files will only use these dependencies but it will not be part of the final bundle. I'am using Gulp for these task in combination of Webpack.
This is task for webpack and transpile my jsx into js where should be only my code, not external libraries
gulp.task('js',['jsx'], function () {
/**This dependency is external, its not part of the bundle */
return gulp.src(config.paths.workDir + config.paths.jsPath + '/**/*.js')
.pipe(webpack({
externals: {
"react": "React"
}
}))
.pipe(rename('onlyCustomJs.js'))
.pipe(gulpif(args.production, uglify()))
.pipe(gulp.dest(config.paths.portlets.newNotePortlet + config.paths.jsPath))
});
This task should create files only with externals libraries and dependency React should be accessible using require in every js webpack file.
gulp.task('global', function(){
/**This will be accessible globally*/
return gulp.src(config.paths.srcDir + config.paths.jsPath + '/global-libs.js')
.pipe(webpack({
output: {
libraryTarget: "var",
library: "React"
}
}))
.pipe(rename('global-libs.js'))
.pipe(gulp.dest(config.paths.portlets.evremTheme + config.paths.jsPath))
});
This file uses global react dependency. But it tells me that React is undefined at var HelloMessage = React..
/** #jsx React.DOM */
var React = require('react');
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
React.renderComponent(HelloMessage({name: "Hello world"}), document.getElementById('example'));
This is global-libs.js file
var React = require('react');
var jQuery = require('jquery');
Thank you!
Maybe It's not to best solution but I solved by these changes.
//These is dependencies which will be bundled in one global-libs.js file and will be accessible from everywhere through require().
module.exports = React = require('react');
module.exports = jQuery = require('jquery');
Webpack only merge these two files and publish them through module.exports
gulp.task('global', function(){
/**This will be accessible globally*/
return gulp.src(config.paths.srcDir + config.paths.jsPath + '/global-libs.js')
.pipe(webpack())
.pipe(rename('global-libs.js'))
.pipe(gulp.dest(config.paths.destDir + config.paths.jsPath))
});
My gulp task for bundling my conde is like this. Only specified externals dependencies which will not be part of the bundle.
gulp.task('js',['jsx'], function () {
/**This dependency is external, its not part of the bundle */
return gulp.src(config.paths.workDir + config.paths.jsPath + '/**/*.js')
.pipe(webpack({
externals: {
"react": "React",
"jquery": "jQuery"
}
}))
.pipe(rename('bundle.js'))
.pipe(gulpif(args.production, uglify()))
.pipe(gulp.dest(config.paths.destDir + config.paths.jsPath))
});
In result I can import dependencies like this.
/** #jsx React.DOM */
var React = require('react');
var jQuery = require('jquery');
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
React.renderComponent(HelloMessage({name: "Hello world"}), jQuery('#example')[0]);

Categories

Resources