Testing React-Bootstrap components with Mocha - reactjs

How can I test React-Bootstrap components with node.js outside the browser? I am using Webpack. Since I'm running headless, I specify the null-loader for styles in my webpack config:
{test: /(\.css|\.less)$/, loader: 'null-loader'}
Nevertheless, I get an error when I run mocha that shows that the style-loader is being used:
webpack:///./~/style-loader/addStyles.js?:14
return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());
^
ReferenceError: window is not defined
at eval (webpack:///./~/style-loader/addStyles.js?:14:30)
at eval (webpack:///./~/style-loader/addStyles.js?:9:47)
at module.exports (webpack:///./~/style-loader/addStyles.js?:31:68)
at eval (webpack:///./~/bootstrap-webpack/bootstrap.config.js?./~/style-loader!./~/css-loader!./~/less-loader!./~/bootstrap-webpack/bootstrap-styles.loader.js:7:38)
[...]
It looks like this is because bootstrap-webpack is using the style loader even though my code isn't.
I've uploaded a full but minimal project to GitHub so you can take a look.

bootstrap-webpack allows you to override its config. Just create file bootstrap.config.js and specify it in the import:
bootstrap.config.js
module.exports = {
styleLoader: 'null-loader',
scripts: {
// add every bootstrap script you need
'transition': false
},
styles: {
// add every bootstrap style you need
"mixins": true,
"normalize": true,
"print": true,
"scaffolding": true,
"type": true,
}
};
App.jsx
import 'bootstrap-webpack!../../bootstrap.config.js';

Related

Typescript Module published in NPM Registry - Cannot find module when used in different project

I created a module using CRA (Create-React-App) - typescript and published the same to npm.
My goal is to add the module as a component in another CRA created typescript project. When I try to import the module it fails with below error.
Cannot find module: 'fbdemots'. Make sure this package is installed.
I do see the modules in the path "node_modules\fbdemots".
I tried the below which did not help
Creating declaration files(d.ts) both in the module and the project which uses the module
Updating the TSConfig as mentioned in below link
Below links does not help, as I cannot change the
"module": "esnext", --> to "CommonJS" since CRA (Create-React-App) does not allow me to.
"moduleResolution": "node", "esModuleInterop" : "true"
`Cannot find module` for my own TypeScript module
Wait! Why I see the fbdemots of node_modules is a project, not component, and it can't be exported at all
If you want to publish a component, you can follow these common steps, of course there are other methods you can try.
If you don't want to use rollup/webpack or feel a bit complicated, you can just export your plain component, and then publish it.
1. Create a component and export it
// index.tsx
import React from 'react'
const Test = (props: {a: string})=> <div>{props.a}</div>
export default Test
2. Using rollup or Webpack to build it to make sure it would be usable for JS modules
Install some necessary modules
yarn add --dev rollup rollup-plugin-typescript2
Then create rollup.config.js file at root, if there are other files like '.css', '.scss', then you should install and add some plugins like rollup-plugin-sass or rollup-plugin-css-only...
// rollup.config.js
import typescript from 'rollup-plugin-typescript2';
// import sass from 'rollup-plugin-sass';
export default {
input: 'index.tsx', // the path of your source file
output: [
{
dir: 'lib',
format: 'cjs',
exports: 'named',
sourcemap: false,
strict: false,
},
],
plugins: [typescript()],
// plugins: [sass({ insert: true }), typescript()],
external: ['react', 'react-dom'],
};
3. Create lib
Using the command of rollup to build it
npx rollup -c
And then prepare package.json, LICENSE, README.md... into lib dir,
finally you can publish it
npm publish ./lib --access public
The end of the last, you can add it as a component in another CRA created typescript project!

Cant use css modules in React with Bootstrap4

I want to use React CSS modules with Bootstrap.
First, I created a project with the create-react-app command. Then, I installed Bootstrap 4 with NPM and included it in my app.js like:
import 'bootstrap/dist/css/bootstrap.css';
I also did npm eject to have access to my Webpack config file.
Meanwhile I wanted to use CSS modules in my layout.js file, so I went to webpack.config.dev.js and changed modules to true:
test: /\.css$/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
modules: true
}
When I change modules to true Bootstrap CSS is not showing correctly. If I change modules to false then Bootstrap is working. Any idea?
Modules: true
Modules: false
Here's a good discussion how to use CSS-modules with other global CSS (e.g. Bootstrap)
https://github.com/css-modules/css-modules/pull/65
Hope it helps.
I had same issue and just loaded bootstrap directly in the index.html from public folder. My project not so big to include bootstrap in the same bundle
P.S.
Actually, I also tried this solution and it works good for me.
https://github.com/css-modules/css-modules/issues/113
I just renamed all of my global css files as .global..css
{
test: /^((?!\.global).)*\.css$/, // anything with .global will not
go through css modules loader
loaders: [
'style-loader',
'css-loader?modules&sourceMap&importLoaders=1&localIdentName=
[name]__[local]___[hash:base64:5]',
'postcss-loader'
]
}

Using Webpack on an existing angular 1.x application

I have an existing, very large, angular 1.x application which runs today ES5 code.
Almost all of the application runs on the same module. My main module is defined in the file "dashboardApp.js".
I want to start using ES6 with modules per component as the app is component structured. For it to run in develpment, I want to start using Webpack.
I tried adding Webpack so I added all the needed npm dependencies and added the following webpack.config.js
var webpack = require('webpack');
module.exports = {
entry: '../app/dashboardApp.js',
output:{
path: __dirname + '/../dst/dist',
filename: 'my.bundle.js'
},
module:{
rules: [{
test: /\.js$/,
loader: 'babel-loader',
exclude: /(node_modules|bower_components)/
}]
}
};
Also, I added to package.json the following property:
"scripts": {
"build": "webpack --config webpack.config.js"
},
and was able to successfully run build and create my.bundle.js. However, when trying to load the app using just the my.bundle.js script, I got an exception:
Uncaught Error: [$injector:modulerr] Failed to instantiate module dashboardApp due to:
Error: [$injector:unpr] Unknown provider: myConsts
myConsts is an angular constant which was included before using Webpack by loading the script and hence my question:
Whats needed in order to transform an existing angular 1.x app that used to load all scripts explicitly to be one Webpack generated script app. What changes I need to do in all my files, that are all defined on the same module, in order to be included in the generated file. I understand that webpack is a module bundler, but I lack the understanding on what I need to do in order to make the old app work with Webpack. Do I need to transform all the files to ES6 module import/export syntax? How does Webpack knows what files to load when the old angular syntax (1 controller/service/constant... per file when all on the same module)? What does it do given the entry point.
Thanks
If your app is using requirejs, then you could achieve it using webpack2. Just configure it properly using rules and aliases. My app too uses requirejs and I successfully managed to replace Grunt with webpack2 after a lot of struggle.
Below is the webpack.config.js file:
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
let basePath = path.join(__dirname, '/');
let config = {
// Entry, file to be bundled
entry: {
'main': basePath + '/src/main.js',
},
devtool: 'source-map',
output: {
// Output directory
path: basePath + '/dist/',
library: '[name]',
// [hash:6] with add a SHA based on file changes if the env is build
filename: env === EnvEnum.BUILD ? '[name]-[hash:6].min.js' : '[name].min.js',
libraryTarget: 'amd',
umdNamedDefine: true
},
module: {
rules: [{
test: /(\.js)$/,
exclude: /(node_modules|bower_components)/,
use: {
// babel-loader to convert ES6 code to ES5 + amdCleaning requirejs code into simple JS code, taking care of modules to load as desired
loader: 'babel-loader',
options: {
presets: ['es2015'],
plugins: []
}
}
}, { test: /jQuery/, loader: 'expose-loader?$' },
{ test: /application/, loader: 'expose-loader?application' },
{ test: /base64/, loader: 'exports-loader?Base64' }
]
},
resolve: {
alias: {
'jQuery': 'bower_components/jquery/dist/jquery.min',
'application': 'main',
'base64': 'vendor/base64'
},
modules: [
// Files path which will be referenced while bundling
'src/**/*.js',
'src/bower_components',
path.resolve('./src')
],
extensions: ['.js'] // File types
},
plugins: [
]
};
module.exports = config;
Let me know if you have any more queries. I still remember how hard I had to try to make things work. WIll be happy to help you!
Putting this here in case anyone else runs into this problem. Essentially what webpack is trying to do is build a dependency graph. Meaning there is an entry point, and then webpack will look at that file and see what it depends on by seeing if there are any imports or require statements in it. It will then travel to the dependency file and bundle that while also looking for more dependencies and so on. In this way, it knows what things need to be loaded before others.
It sounds like you didn't alter your source code to import or require any of the module's dependencies, so Webpack simply built that one file you pointed it to instead of all of the files of your app.
Lets say ModuleA depends on ModuleB and ModuleC.
in ModuleA.js, you'll import (or require) moduleB as well as ModuleC.
In both ModuleB and ModuleC, you'll need to export them and make sure your exporting the .name property from the module since AngularJS wants strings for its dependencies.
The tricky thing about using AngularJS with Webpack, is that Angular has its own Module system which is different from the commonJS pattern or ESModules, so its a bit of an odd combination.
Softvar's solution above works because he told webpack what to bundle when defining his modules under the resolve property. If all of your sub modules are exported, another solution to bundling all of your angular files into one parent module to export, is like this, where the file is index.js and webpack looks here as its entry point:
const modules = [];
function importAll(webpackContext) {
// the webpackContext parameter is a function returned after invoking require.context() that has
// access to all of the resolved paths defined in the require.context call.
// The keys will be an array of all of the resolved module paths returned from the initial
// require.context invocation within the importAll invocation a number of lines below this declaration.
webpackContext.keys()
// this will fetch each module itself and give us access to all of the exports from that module.
// Since we are exporting the angular modules as the default export from all of our index files,
// we are just pushing the default property into the modules array. In this case the default property
// is the string name of the angular module.
.forEach(modulePath => modules.push( webpackContext(modulePath).default) );
}
// recurse through all sub directories in ./src and find the path for each index.js file.
importAll(require.context("./src/", true, /index\.js$/));
// take all of the module's name strings and spread them out as module dependencies.
// export the single module all glued together.
export default angular.module("YOUR_MODULE_NAME", [...modules]).name;

babel: polyfill Array.from for IE11 support

I'm currently having trouble getting my React application working in IE11. The problem seems to be that some of the newer ES6 stuff isn't available in IE11. So my goal is to polyfill the missing functionality. I'm using nwb [1] which is a zero-configuration setup for React applications. However, I'm unsure how to configure Babel (or Webpack ?) to polyfill certain methods like Array.from. It looks like fetch, Promise, and Object.assign are all polyfill-ed but not Array.from for example. Any help would be greatly appreciated.
Here is my nwb.config file:
module.exports = {
type: 'react-app',
webpack: {
define: {
VERSION: JSON.stringify(require('./package.json').version),
HOSTNAME: JSON.stringify(process.env.NODE_ENV === 'production' ?
'https://xyz.azurewebsites.net' :
'http://localhost:8080')
},
rules: {
babel: {
test: /\.jsx?/
}
},
extra: {
resolve: {
extensions: ['.jsx']
},
devtool: '#inline-source-map'
},
html: {
favicon: 'src/img/favicon.ico'
}
}
};
Thanks,
[1] A toolkit for React app. https://github.com/insin/nwb
Sounds like you need to add babel-polyfill to your project.
This will emulate a full ES2015+ environment and is intended to be
used in an application rather than a library/tool. This polyfill is
automatically loaded when using babel-node.
This means you can use new built-ins like Promise or WeakMap, static
methods like Array.from or Object.assign, instance methods like
Array.prototype.includes, and generator functions (provided you use
the regenerator plugin). The polyfill adds to the global scope as well
as native prototypes like String in order to do this.
The easiest way for you would probably be to import it at the top of your main js file:
import 'babel-polyfill';

using webpack ProvidePlugin in React storybook custom webpack config

I've built a wrapper package for drag and drop in React, and I added storybook examples.
Since in my consumer React is exposed globally, i'm not importing React explicitly.
In the storybook examples I need to supply React as part of the custom webpack config, but for some reason it can't resolve React and I get a ReferenceError: React is not defined
This is the package - https://github.com/fiverr/drag_n_drop_package
And this is the custom webpack config file:
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.ProvidePlugin({
React: 'react'
})
],
module: {
loaders: [
{
test: /\.scss$/,
loader: 'style!raw!sass'
}
]
}
};
This is really strange but your storybook webpack.config.js is mixing webpack v1/v2.
Importing webpack as
const webpack = require('#kadira/storybook/node_modules/webpack');
solves it because it uses the same webpack reference that storybook is using (v1).
I found the following code in webpack.config.js at github:
externals: {
react: 'React'
}
It looks as this question. If it needs to load the React lib from external, like CDN. The page has to be sure have a script tag for importing React lib. And make sure this script tag is in front of the bundle.js or the file which it generated by webpack, so the Object of React will exist when the following code needs to use React, such as:
<script src="./react.js"></script>
<script src="./bundle.js"></script>

Resources