I have a VueJS 2 application in which I'm trying to load specific components depending on different flags in a config JSON file.
My file structure is as follows:
root
config.json
> src
>> client
>>> components
>>>> dashboard
>>>>> MenuBarBrand.vue
> product
>> product01
>>> client
>>>> components
>>>>> branding
>>>>>> MenuBrand.vue
>> product02
>>> client
>>>> components
>>>>> branding
>>>>>> MenuBrand.vue
At the moment I've tried 2 different methods:
Using the webpack import syntax in my MenuBarBrand component:
<template>
<b-navbar-brand href="/dashboard">
<MenuBrand />
</b-navbar-brand>
</template>
<script>
import config from '../../../../config.json';
const MenuBrand = import(`../../../../product/${config.product}/components/branding/MenuBrand`);
export default {
name: 'MenuBarBrand',
components: {
'MenuBrand',
},
}
</script>
which results in the following error:
or the Vue Async Components local registration syntax:
<template>
<b-navbar-brand href="/dashboard">
<MenuBrand />
</b-navbar-brand>
</template>
<script>
import config from '../../../../config.json';
export default {
name: 'MenuBarBrand',
components: {
'MenuBrand': () => import(`../../../../product/${config.product}/components/branding/MenuBrand`)
},
}
</script>
which results in the following error:
Are there any clear errors that I'm making or are there any specific babel/webpack plugins needed to enable this functionality?
Edit: Adding my loader configuration based on a comment I received:
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
scss: [
'vue-style-loader',
'css-loader',
'sass-loader',
],
sass: [
'vue-style-loader',
'css-loader',
'sass-loader?indentedSyntax',
],
},
},
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]',
},
},
{
test: /\.css$/,
loader: 'style-loader!css-loader',
},
{
test: /\.(ttf|otf|eot|woff(2)?)(\?[a-z0-9]+)?$/,
loader: 'file-loader?name=fonts/[name].[ext]',
},
],
},
I solved this through an alternate method.
In the webpack config I pull in my product flag and create a path:
const config = require('./config.json');
const fs = require('fs');
const path = require('path');
const productPath = path.resolve(__dirname, 'product', config.product);
Then I set up an alias in the webpack config using this path:
resolve: {
alias: {
menuBrandingPath: productPath,
},
extensions: ['*', '.js', '.vue', '.json'],
},
This path is then used in my Vue component to import the proper component:
<template>
<MenuBrand />
</template>
<script>
import MenuBrand from 'menuBrandingPath/client/components/branding/MenuBrand'; // menuBrandingPath is an alias in the webpack config
export default {
name: 'MenuBar',
components: {
MenuBrand,
},
}
</script>
I've intentionally left out error checking with fs and the fallback path I used to make this example easier to understand. Hopefully it helps someone! :)
You need to use the vue-loader webpack plugin to process the .vue-files in your webpack setup. That enables the () => import(...) syntax.
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
(other loaders....)
]
},
Or, using requireinstead in your original example:
<template>
<b-navbar-brand href="/dashboard">
<MenuBrand />
</b-navbar-brand>
</template>
<script>
import config from '../../../../config.json';
const MenuBrand = require(`../../../../product/${config.product}/components/branding/MenuBrand`);
export default {
name: 'MenuBarBrand',
components: {
'MenuBrand',
},
}
</script>
Related
I am begining with React using Webpack to make the configuration. I made all step by step. No error message on console or browser but the h1 that I want to insert doesn't appear.
I know that React is v.18 but I am using React v.17
App.jsx
import React from 'react'
const App = () => {
return (
<h1>Holaaa</h1>
);
}
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/app.jsx';
ReactDOM.render (<App/>, document.getElementById ("Hello"))
webpack.config.js
const path = require ("path");
const HtmlWebpackPlugin = require ('html-webpack-plugin')
const MiniCssExtractPlugin = require ('mini-css-extract-plugin')
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve (__dirname, 'dist'),
filename: "bundle.js"
},
mode: "development",
resolve: {
extensions: ['.js', '.jsx']
},
module: {
rules: [
{test: /\.(js|jsx)$/,
exclude: "/node_modules",
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react']
}
}},
{test: /\html$/,
use: [
{loader: 'html-loader'}
] },
{test: /\.sa[ac]ss$/,
use: ['css-loader',
'style-loader',
'sass-loader']}
]
},
plugins: [
new HtmlWebpackPlugin ({
inject: true,
template: "./public/index.html",
filename: '/menu.html'
}), new MiniCssExtractPlugin ({
filename: "[name].css"
})
]
}
index.html
<title>Document</title>
</head>
<body>
<div id="Hello"> </div>
</body>
</html>
I found the solution. It was the filename config. Was /menu.html. So when localhost was with /menu.html, React render the h1 element.
So, to make render I only have to change /menu.html for index.html in the filename config, refresh and was done!
I am developing a npm package and use there webpack 5.
This is my config
const path = require('path') // resolve path
module.exports = {
mode: 'development',
resolve: {
extensions: ['.js', '.jsx'], // we can import without typing '.js or .jsx'
},
entry: {
index: path.join(__dirname, 'src/index.jsx'),
},
output: {
path: path.resolve(__dirname, './dist'),
filename: 'index.js', // for production use [contenthash], for developement use [hash]
library: {
type: 'module',
},
environment: { module: true },
},
experiments: {
outputModule: true,
},
devtool: 'eval',
module: {
rules: [
{
test: /\.(css|scss|sass)$/,
use: [
{
loader: 'style-loader', // creates style nodes from JS strings
},
{
loader: 'css-loader', // translates CSS into CommonJS
},
{
loader: 'sass-loader', // compiles Sass to CSS
},
],
},
{
test: /\.(js|jsx)$/,
exclude: /nodeModules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.(png|svg|jpe?g|gif)$/i,
use: [
{
loader: 'file-loader',
},
],
},
{
test: /.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
exclude:
/images/ /* dont want svg images from image folder to be included */,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'fonts/',
name: '[name][hash].[ext]',
},
},
],
},
],
},
externals: {
react: 'React',
'react-dom': 'ReactDOM',
},
plugins: [],
}
When I want to import components from this library I get this error:
Failed to resolve import "React" from "..my-package/dist/index.js". Does the file exist?
I think this has something to do with externals react and react-dom. But when I remove the externals from webpack config I get the error that react should be only installed once when using react hooks.
In my main application I am using vite for bundeling but I tried it also with create-react-app and have the same problem.
My Library Component:
import React, { useState } from 'react'
const App = () => {
const [counter, setCounter] = useState(0)
return <div>{counter}</div>
}
export default App
This is how I am using it with npm-link:
import React from "react";
import Test from "my-package";
const App = () => {
return <Test />;
};
export default App;
Here is the repo with the code https://github.com/guitar9/webpack-bug
I am learning how to make custom component or library and publish on npm. I found a free tutorial here:
https://www.udemy.com/course/your-custom-react-component/learn/lecture/13561884#overview
github link
https://github.com/davidcsejtei/custom-button
But I am facing one problem .he created a simple component custom button
import React, { Component } from 'react';
import '../style/button.scss';
export default class CustomButton extends Component {
render() {
return(
<button>Custom button</button>
);
}
}
but when we create a build it include react library in his build so now it's size increase to 7.5kb.It should be below 2kb as it is small component and it is used in another project
In other ways custom component use react dependency from there parent component . Can we remove this react dependency in build ?
Here is the webpack config:
const webpack = require('webpack');
const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'custom-button.js',
library: 'custom-button',
libraryTarget: 'umd',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ["#babel/preset-env", "#babel/preset-react"]
}
}
},
{
test: /\.scss$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'sass-loader'
}
]
}
]
},
optimization: {
minimizer: [new UglifyJsPlugin()]
},
plugins: [
new CleanWebpackPlugin(['dist'])
]
}
any update ?
In order to exclude react out of your build with webpack, you just simply declare externals in your configuration like below:
externals: {
react: "react",
}
As you output with your umd module above, it will require react as the dependency in the build which means it will consume the react at the parent (consuming) repo:
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("react"));
// ...
I have been trying to use external css on my React project. I am using webpack with babel. I have configured css, js and jsx loaders on my project. As a matter of fact my project is able to compiled successfully yet I couldn't able to style applied on my html.
Here is my style-header.css file:
.LogoMargin {
margin-top: 10px;
margin-left: 10px;
}
Here is my jsx file in which I want to use css style
import React,{Component} from 'react';
import { withStyles } from 'material-ui/styles';
import TextField from 'material-ui/TextField';
import logo from '../resources/images/logo.png';
import '../resources/style/style-header.css';
class Header extends Component {
render () {
return(
<div>
<span>
<img className="LogoMargin" src={logo} height="60" width="200" alt="logo" />
</span>
<TextField
id="search"
label="Search"
type="search"
/>
</div>
)
}
}
export default Header;
Here webpack config file:
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'eval-source-map',
entry: __dirname + "/app/index.js",
output: {
path: __dirname + "/build",
filename: "bundle.js"
},
module: {
loaders: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.css$/,
exclude: /node_modules/,
loader: 'css-loader'
},
{
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: {
bypassOnDebug: true,
},
},
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: __dirname + "/index.tmpl.html"
}),
new webpack.HotModuleReplacementPlugin()
],
devServer: {
historyApiFallback: true,
inline: true,
stats: {colors: true},
hot: true
}
}
Add style loader for handling css as well.
Because you didn't provide webpack version, I cannot provide any code, but I'm sure you will figure out how to use it.
https://github.com/webpack-contrib/style-loader
You should add "style-loader" for your webpack configuration. You can provide it in array as the following. Also, I have an example in this repo:
https://github.com/burakhanalkan/simple-react-materialui-app-starter/blob/master/webpack.config.js
{
test: /\.css$/,
use: [
"style-loader",
"css-loader"
]
},
Well I was able to solve this problem as proposed by answers to use style-loader and also I made some changes to my webpack config file which are as follow:
test: /\.css$/,
exclude: /node_modules/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" ,
query: {
modules: true,
localIdentName: '[name]__[local]___[hash:base64:5]'
}}
]
But I wonder when I set up react environment using Create React App I was able to use styles without using css module loader.
I am trying to extract SCSS to CSS on my react.js app using webpack plugin: extract-text-webpack-plugin. I am not getting any errors but i can't see any style on my page when i compile. In the following code i am simply trying to change the color of hello world rendered on the screen from black to red. Here are my files:
webpack.config.js
var webpack = require('webpack');
var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
devtool: 'inline-source-map',
entry: [
'webpack-dev-server/client?http://127.0.0.1:8080/',
'webpack/hot/only-dev-server',
'./src/index.js',
'./sass/styles.scss'
],
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js'
},
resolve: {
modules: ['node_modules', 'src'],
extensions: ['.js', '.jsx']
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: ['react-hot-loader', 'babel-loader']
},
{ // regular css files
test: /\.css$/,
loader: ExtractTextPlugin.extract({
loader: 'css-loader?importLoaders=1',
}),
},
{ // sass / scss loader for webpack
test: /\.(sass|scss)$/,
loader: ExtractTextPlugin.extract(['css-loader', 'sass-loader'])
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new ExtractTextPlugin("styles.css")
]
};
styles.scss
$color : red;
.hello{
font-color: $color;
text-align: center;
}
app.js
import React from 'react';
export default class App extends React.Component {
render() {
return (
<div>
<h1 className = "hello">Hello World</h1>
</div>);
}
}
index.js
import React from 'react';
import { render } from 'react-dom';
import App from './components/app';
render ( <App />, document.getElementById('app'));
What i'm I missing?
you're missing style-loader from your loader chain.
from the sass-loader docs:
Chain the sass-loader with the css-loader and the style-loader to immediately apply all styles to the DOM.
// webpack.config.js
module.exports = {
...
module: {
rules: [{
test: /\.scss$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "sass-loader" // compiles Sass to CSS
}]
}]
}
};
you need import styles.scss in code index.js
import 'yourlink/styles.scss'