I try to implement wow.js using react and webpack.
I install it via npm.
npm install --save wow.js
It install perfectly. Now the problem is how to import it properly. I can't make it work keep getting undefined.
I've tried few way:
First:
import wow from 'wow.js';
But webpack can't compile it. It says the module cannot be found. Even I using complete url import wow from /node_modules/wow.js
Second:
I'm using this solution from here:
require('imports?this=>window!js/wow.js');
But I still get cannot find modules (i change the path to my node_modules).
Third:
From here:
I'm using the expose module and try to new WOW().init(); it says Wow is undefined.
I'm not using his first solution because I want my html to look simple only has bundle.js script.
I can't found any other solution. What should I do to make it work?.
Thanks!
my webpack.config.js:
module.exports = {
entry: [
'webpack-dev-server/client?http://localhost:8080',
'bootstrap-loader',
'webpack/hot/only-dev-server',
'./src/js/index.js'
],
output: {
path: __dirname + "/build",
publicPath: "/build/",
filename: 'bundle.js'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
],
module: {
loaders: [
{
exclude: /node_modules/,
loader: 'react-hot!babel'
},
{
test: /\.css$/,
loader: 'style!css!postcss'
},
{
test: /\.scss$/,
loader: 'style!css!postcss!sass'
},
{ test: /\.(woff2?|ttf|eot|svg|otf)$/, loader: 'url?limit=10000' },
{
test: 'path/to/your/module/wow.min.js',
loader: "expose?WOW"
}
]
},
resolve: {
extensions: ['', '.js', '.jsx']
},
devServer: {
historyApiFallback: true,
contentBase: './'
},
postcss: [autoprefixer]
};
Alternative option without updating your wepack config.
Install WOW.js: npm install wowjs
Import in your component: import WOW from 'wowjs';
Under componentDidMount() of your component: new WOW.WOW().init();
import React, {Component} from 'react';
import WOW from 'wowjs';
class Cmp extends Component {
componentDidMount() {
new WOW.WOW().init();
}
render() {
/* code */
}
}
export default Cmp;
Do the following steps
Install exports-loader
npm i exports-loader --save-dev
Add to webpack.config.js this loader
{
test: require.resolve('wow.js/dist/wow.js'),
loader: 'exports?this.WOW'
}
add import to your app
import WOW from 'wow.js/dist/wow.js';
You can also change .call(this) to .call(window) (wow.js last line). Found this solution here https://foundation.zurb.com/forum/posts/46574-how-to-add-js-library-from-bower
Related
I'm working on a component library that wraps some of the MaterialUI components and implements others to be used in a larger project. While setting up the library I had to setup webpack in order to be able to import and bundle images and css files in my library.
This library is located nested in the folder of the main project, where I add it as a dependency with npm i ./shared/path_to_library. this seems to work fine, since the typescript is working correctly and the npm start gives me no error. Then when I open it in a browser I get the following error page:
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
But this error only occurs if I try to use any component from #mui/material inside my library. Exporting handmade components and using them in the main project works fine, but using any material component wrapped by my own component and then using it in the project brings me to this error. I also tried to move from webpack to rollup but I ended up getting the same problem.
Here are my config files for webpack and rollup:
rollup.config.js
import resolve from "#rollup/plugin-node-resolve";
import commonjs from "#rollup/plugin-commonjs";
import typescript from "#rollup/plugin-typescript";
import dts from "rollup-plugin-dts";
const pkg = require("./package.json");
const config = [
{
input: "src/index.ts",
output: [
{ file: pkg.main, format: "cjs", sourcemap: true },
{ file: pkg.module, format: "esm", sourcemap: true },
],
plugins: [
resolve(),
commonjs(),
typescript({ tsconfig: "./tsconfig.json" }),
],
},
{
input: "lib/esm/types/index.d.ts",
output: [{ file: "lib/index.d.ts", format: "esm" }],
plugins: [dts()],
},
];
export default config;
webpack.config.js
const path = require("path");
module.exports = {
entry: "./src/index.ts",
mode: "development",
output: {
path: path.resolve(__dirname, "lib"),
filename: "[name].js",
libraryTarget: "umd",
library: "my-core-library",
umdNamedDefine: true,
},
devtool: "source-map",
module: {
rules: [
{
test: /\.css?$/,
use: ["style-loader", "css-loader"],
exclude: /node_modules/,
},
{
test: /\.tsx?$/,
use: ["babel-loader", "ts-loader"],
exclude: /node_modules/,
},
{
test: /\.(png|jpe?g|gif|svg)$/,
use: ["file-loader"],
exclude: /node_modules/,
},
],
},
resolve: {
extensions: [".ts", ".tsx", ".js", ".jsx"],
},
externals: [
{
react: "react",
"react-dom": "react-dom",
"#mui/material": "#mui/material",
"#emotion/react": "#emotion/react",
"#emotion/styled": "#emotion/styled",
"#mui/lab": "#mui/lab",
},
],
};
I'm running out of ideas :(
This is probably happening because multiple instances of React are loaded. You can check with npm ls react, all react packages should be deduped
A short term solution is to link the react from the library, ie
npm link ../shared/path_to_library/node_modules/react
However you would have to re-link that everytime you install an npm package.
I think you need to configure your .babelrc as following:
"presets": ["#babel/preset-env", "#babel/preset-react", "#babel/preset-typescript", "jest"],
"plugins": [
[
"babel-plugin-transform-imports",
{
"#material-ui/core": {
"transform": "#material-ui/core/${member}",
"preventFullImport": true
},
"#material-ui/icons": {
"transform": "#material-ui/icons/${member}",
"preventFullImport": true
}
}
]
]
I've created boilder plate project with webpack, react, typescript etc. but whenever I build my project, webpack throw this errors on my entry point that Cannot resolve other modules (which is just simple Login component)
This is my webpack's error message
ERROR in ./src/index.tsx
Module not found: Error: Can't resolve './components/Login' in '/Users/myname/Desktop/Projects/front/src'
# ./src/index.tsx 6:14-43
This is my index.tsx file
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import Login from './components/Login';
ReactDOM.render(
<BrowserRouter>
<Login />
</BrowserRouter>,
document.getElementById('root')
);
And this is my Login components, which webpack cannot resolve
import * as React from 'react';
export default () => <div>Login</div>;
This is my webpack config and package.json's scripts
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: './src/index.tsx',
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'awesome-typescript-loader',
options: {
useCache: true,
reportFiles: ['src/**/*.{ts,tsx}']
}
},
{
enforce: 'pre',
test: /\.js$/,
loader: 'source-map-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'template/index.html'
})
],
mode: 'production',
output: {
path: path.resolve(__dirname, 'build/'),
filename: 'bundle.[hash].js'
},
plugins: [new CleanWebpackPlugin()]
};
package.json's scripts
"scripts": {
"build": "webpack"
},
I tried minimize my project as possible so you can focus on this single problem, why the hack my webpack cannot resolve ordinary component file? you can find this minimized project on https://github.com/sh2045/myproblem
you can just clone it, and run
npm i
npm run build
and you can see error message, please help :(
Instead of using awesome-typescript-loader why don't you try the loader's recommended by webpack for typescript
To fix your problem,
Install this node package npm install --save-dev typescript ts-loader. This is the loader that does ts to js conversion.
You need to remove awesome-typescript-loader and use ts-loader in webpack.config.js. Below is the updated webpack.config.js. You can use this configuration and execute npm run build and verify if your webpack bundles the project without errors
Modified webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: './src/index.tsx',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
enforce: 'pre',
test: /\.js$/,
loader: 'source-map-loader'
}
]
},
resolve: {
extensions: [ '.tsx', '.ts', '.js' ]
},
plugins: [
new HtmlWebpackPlugin({
template: 'template/index.html'
})
],
mode: 'production',
output: {
path: path.resolve(__dirname, 'build/'),
filename: 'bundle.[hash].js'
},
plugins: [new CleanWebpackPlugin()]
};
Note When i downloaded & setup your project from your git, this package npm i acorn --save was missing in your package.json i believe. so i had to install it manually
Firstly, I scaffolded a vuejs project as a test container from vue-cli.
Then I create a npm package "vue-npm-example" from a Vuejs component in local environment and imported in the above testing project.
In the package,
I ran npm link and in the project I ran npm link vue-npm-example,
Example.vue
<template>
<div id="vue-npm-example">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: 'vue-npm-example',
data() {
return {
msg: "Welcome to Your Vue.js App"
}
},
mounted() {
console.log('this is in compoennt file')
}
};
</script>
<style lang="scss">
</style>
main.js
import Example from './components/Example.vue'
export function install(Vue, options) {
options = {
installComponents: true
}
if (options.installComponents) {
Vue.component('vuejs-example', Example)
}
}
export default Example
webpack.config.js
let path = require('path')
let webpack = require('webpack')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'index.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
},
{
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader'
]
},
{
test: /\.sass$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader?indentedSyntax'
]
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
// Since sass-loader (weirdly) has SCSS as its default parse mode, we map
// the "scss" and "sass" values for the lang attribute to the right configs here.
// other preprocessors should work out of the box, no loader config like this necessary.
'scss': [
'vue-style-loader',
'css-loader',
'sass-loader'
],
'sass': [
'vue-style-loader',
'css-loader',
'sass-loader?indentedSyntax'
]
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.common.js',
'#': resolve('src')
},
extensions: ['*', '.js', '.vue', '.json']
},
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
performance: {
hints: false
},
devtool: '#eval-source-map',
node: {
fs: 'empty'
},
watch: true
}
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
// new webpack.optimize.UglifyJsPlugin({
// sourceMap: true,
// compress: {
// warnings: false
// }
// }),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
Then in the testing project
I do
import Vue from 'vue'
import Example from 'vue-npm-example'
Vue.component('example', Example)
and use it like
<example></example>
I got error:
[Vue warn]: Failed to mount component: template or render function not defined.
I set the vue alias in the webpack config files for both package and project. The package got pulled in correctly because when I do console.log() in the package's main.js, it logs in the testing project. But no matter what I tried, the component in the package still won't work in the testing project.
Any suggestions?
npm link create an symlink, but when import the local npm package, I need to specify the full address of the package. In my case, I have to do import customComponent from './node_modules/custom-component/dist/index.js'
import customComponent from 'custom-component`.
I'd use npm pack instead (some downsides of using npm link to test your npm package locally: https://blog.vcarl.com/testing-packages-before-publishing/)
In the package
Run npm pack
In the project
Run npm install (path-to-package)/package-name-0.0.0.tgz
Then import/install the package in your main.js:
import MyPackage from 'package-name'
// This runs your 'install' method which registers your component globally with Vue.component(...)
Vue.use(MyPackage);
Some useful links
Packaging Vue components for npm: https://v2.vuejs.org/v2/cookbook/packaging-sfc-for-npm.html
Vue npm walkthrough: https://www.telerik.com/blogs/vuejs-how-to-build-your-first-package-publish-it-on-npm
Global component registration: https://v2.vuejs.org/v2/guide/components-registration.html#Global-Registration
I want to build a react component library as a node module to then import it into different projects. But if I try to import a component it just returns an empty object.
button.jsx:
import React, {Component} from 'react'
export class Button extends Component {
render() {
return <button className='btn'>Hello Button comp</button>
}
}
export default Button
index.js
var Button = require('./button/button').default;
module.exports = {
Button: Button
}
webpack.config.js
const Path = require('path');
module.exports = {
resolve: {
extensions: ['.js', '.jsx']
},
entry: {
app: './src/components/index.js'
},
output: {
path: __dirname,
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.jsx$/,
loader: 'babel-loader',
query: {
presets: [
'es2015',
'react'
]
},
exclude: /node_modules/,
include: [
Path.resolve(__dirname, 'src')
]
},
{
test: /\.js$/,
loader: 'babel-loader',
query: {
presets: [
'es2015',
'react'
]
},
exclude: /node_modules/,
include: [
Path.resolve(__dirname, 'src')
]
}
]
}
}
Main property in package.json is bundle.js
I figured out that when I import Button in a project it is just an empty object. It seems to me as if webpack doesn't bundle the index file properly. Any ideas what could be wrong here?
A webpack bundle does not expose your exports by default, as it assumes that you're building an app and not a library (which is the far more common use of webpack). You can create a library by configuring output.library and output.libraryTarget.
output: {
path: __dirname,
filename: 'bundle.js',
library: 'yourLibName',
libraryTarget: 'commonjs2'
},
output.libraryTarget is the format of the module, which would also allow you to expose the library as a global variable. commonjs2 is the module format that Node uses. See What is commonjs2? for the difference between commonjs and commonjs2.
Since you're using React, you'll expect that the consumer of the library will have React present as a dependency and therefore you don't want to include it in your bundle. To do that you can define it as an External. This is shown in Authoring Libraries, which walks you through a small example.
i'm developing an application with react.js. My application is growing up. So i had little trouble with imports. For example i have a component named foo i'm using it in many places.
import foo from '../../components/foo';
import foo from '../components/foo';
import foo from '../../../components/foo';
As you can see its dirty, not good. So i searched to fix it and i found a solution with webpack. Also i read that title (Configure Webpack’s modules resolution to avoid nested imports) in this article
I added this code into my webpack.config.js file
modules: [
'node_modules',
path.resolve(__dirname, 'src')
]
So my resolve object looks like this
export default {
resolve: {
modules: [
'node_modules',
path.resolve(__dirname, 'src')
],
extensions: ['*', '.js', '.jsx', '.json']
},
...
After that i am able to use import my foo component in anywhere like this.
import foo from 'components/foo';
Everything is okay so far. But problem shows up in test files.
When i try to test foo component it says
Cannot find module 'components/foo' from 'foo.js'
Example test file.
foo.spec.js
import React from 'react';
import foo from 'components/foo';
describe('(Component) foo', () => {
it('should render foo', () => {
expect(true).toBe(true);
});
});
Here is the first problem. I can not import foo like this.
Note: My test file is not in src folder it is in the test folder.
So i changed the path like this then it worked.
import foo from '../../../src/components/foo';
Tes passed everything is looks fine. But we still have the path problem in test files.
Lets try to import another component in foo component.
foo.js
import bar from 'components/admin/bar';
Here is the second problem. Test file FAILED error message is
Cannot find module 'components/admin/bar' from 'foo.js'
I moved my test file in to my foo.js file. But didn't worked.
Here is my whole webpack.config.js
import webpack from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import autoprefixer from 'autoprefixer';
import path from 'path';
export default {
resolve: {
modules: [
'node_modules',
path.resolve(__dirname, 'src')
],
extensions: ['*', '.js', '.jsx', '.json']
},
devtool: 'inline-source-map', // more info:https://webpack.github.io/docs/build-performance.html#sourcemaps and https://webpack.github.io/docs/configuration.html#devtool
entry: [
// must be first entry to properly set public path
'./src/webpack-public-path',
'webpack-hot-middleware/client?reload=true',
path.resolve(__dirname, 'src/index.js') // Defining path seems necessary for this to work consistently on Windows machines.
],
target: 'web', // necessary per https://webpack.github.io/docs/testing.html#compile-and-test
output: {
path: path.resolve(__dirname, 'dist'), // Note: Physical files are only output by the production build task `npm run build`.
publicPath: '/',
filename: 'bundle.js'
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development'), // Tells React to build in either dev or prod modes. https://facebook.github.io/react/downloads.html (See bottom)
__DEV__: true,
//'API_URL': API_URL.dev
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new HtmlWebpackPlugin({ // Create HTML file that includes references to bundled CSS and JS.
template: 'src/index.ejs',
minify: {
removeComments: true,
collapseWhitespace: true
},
inject: true
}),
new webpack.LoaderOptionsPlugin({
minimize: false,
debug: true,
noInfo: true, // set to false to see a list of every file being bundled.
options: {
sassLoader: {
includePaths: [path.resolve(__dirname, 'src', 'scss')]
},
context: '/',
postcss: () => [autoprefixer],
}
})
],
module: {
rules: [
{test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel-loader']},
{test: /\.eot(\?v=\d+.\d+.\d+)?$/, loader: 'file-loader'},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url-loader?limit=10000&mimetype=application/font-woff'
},
{test: /\.[ot]tf(\?v=\d+.\d+.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/octet-stream'},
{test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml'},
{test: /\.(jpe?g|png|gif)$/i, loader: 'file-loader?name=[name].[ext]'},
{test: /\.ico$/, loader: 'file-loader?name=[name].[ext]'},
{
test: /(\.css|\.scss|\.sass)$/,
loaders: ['style-loader', 'css-loader?sourceMap', 'postcss-loader', 'sass-loader?sourceMap']
}
]
}
};
How can i solve?
Thanks for your help.
Webpack is not used during test execution. Since you are using babel the babel-plugin-module-resolver https://github.com/tleunen/babel-plugin-module-resolver should solve the issue:
in your .babelrc file
{
"plugins": [
["module-resolver", {
"root": ["./src"]
}]
]
}
A more cleaner approach would be to create an alias in your .babelrc file and then import from that alias, for instance:
{
"plugins": [
["module-resolver", {
"alias": {
"#app": "./src"
}
}]
]
}
And in your file:
import foo from '#app/components/foo'
That way you have no naming conflicts and your paths are nice and short.
Problem solved after i changed this jest object in package.json file.
"jest": {
"moduleDirectories": [
"node_modules",
"src"
]
...