Error for ReactJs.Net server side rending with ES6 - reactjs.net

I have been working withe ReactJs.Net and MVC5 application and facing issues with server side rending while using ES6 and babel transpiler. I used expose-loader for exposing the component globally. But it is working only in ES5 syntax . If I use ES6 and Webpack for bundling i am getting the below error in #Html.React() function.
Error while rendering "Hello" to "react_Hq6cd5QfaUu26XrhGgZA": Script threw an exception: Minified React error #130; visit http://facebook.github.io/react/docs/error-decoder.html?
Code for ~Jsx/Components/Helloworld.jsx
import React, {Component} from 'react';
export default class Helloworld extends Component {
render() {
return (
<div>Hello {this.props.name} ,This is my first react component.</div>
);
}
}
Code for ~Jsx/server.jsx
import Hello from 'expose?Hello!./components/Helloworld' ;
webpack.config.js
var path = require('path');
var webpack = require('webpack');
module.exports =
{
entry: ['./Jsx/server.jsx'],
output: { path: './build', filename: 'main.js' },
module: {
loaders: [
{
test: /\.jsx$/,
loader: ['babel-loader'],
include: path.resolve(__dirname, 'Jsx'),
query: {
presets: ['es2015', 'react']
}
},
]
},
resolve: {
extensions: ['', '.js', '.jsx']
}
//watch:true
}
RectConfig.cs
ReactSiteConfiguration.Configuration
.SetLoadBabel(false)
.AddScriptWithoutTransform("~/build/main.js");
The above code works fine if i use the below ES5 syntax for Helloworld component
var React=require('react');
var Helloworld = React.createClass({
render: function() {
return (
<div>
Hello {this.props.name} ,This is my first react component.
</div>
);
}
});
module.exports=Helloworld;
Please help me if someone knows the solution.

Related

Load SVGs components in storybook VUE not working

Hello everyone I'm using vue 3 with storybook 6.5.16 and when i import the SVGs as a component using svg-inline-loader i get the following error in storybook app:
enter image description here
(Failed to execute 'createElement' on 'Document' svg is not a valid name)
Storybook main.js
const path = require('path');
module.exports = {
stories: [
'../src/**/*.stories.mdx',
'../src/**/*.stories.#(js|jsx|ts|tsx)',
],
addons: [
'#storybook/addon-links',
'#storybook/addon-essentials',
'#storybook/addon-interactions',
],
framework: '#storybook/vue3',
core: {
builder: '#storybook/builder-webpack5',
},
webpackFinal: async (config, { configType }) => {
// `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
config.module.rules.push({
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
{
loader: "sass-loader",
options: {
additionalData: `
#import "#/assets/scss/main.scss";
`,
implementation: require('sass'),
},
},
],
});
(() => {
const ruleSVG = config.module.rules.find(rule => {
if (rule.test) {
const test = rule.test.toString();
const regular = /\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/;
const regularString = regular.toString();
if (test === regularString) {
return rule;
}
}
});
ruleSVG.test = /\.(ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/;
})();
config.module.rules.push({
test: /\.svg$/,
use: ['svg-inline-loader'],
});
config.resolve.alias['#'] = path.resolve('src');
return config;
},
}
package.json file
enter image description here
SVG Vue components
<template>
<div
ref="icon"
class="v-icon"
#click="onClick"
>
<component
:is="iconName"
class="v-icon__svg"
/>
</div>
</template>
<script>
import Cards from '#/assets/icons/Cards.svg';
export default {
name: 'VIcon',
components: {
Cards,
},
props: {
iconName: {
type: String,
required: true,
},
},
};
</script>
.babelrc file
{
"presets": ["#babel/preset-env", "#babel/preset-react"]
}
i tried to use vue-svg-loader to replace svg-inline-loader but it didn't work and I got another error while building the app
ModuleBuildError: Module build failed: Error: Cannot find module './Block'
I also tried to use babel-loader in conjunction with vue-svg-loader but unfortunately I also got an error:
enter image description here
has anyone come across this or can you show your use cases of using SVGs components in Storybook and Vue 3?

How to use Environment Variables inside Vue3+Vite component library?

I have created a component as part of my component library that I am building with Vue3 and Vite. Everything works well, except when I try to use environment variables. I want the app that consumes this component library to be able to provide the component with environment specific data.
I have played around and found that if I have a .env file as part of the component library project, I am able to access those variables, but I want to be able to provide that during runtime and not during build time.
Here is my vite.config.ts
import { defineConfig } from "vite";
import { resolve } from "path";
import vue from "#vitejs/plugin-vue";
import dts from "vite-plugin-dts";
export default ({ mode }) => {
return defineConfig({
optimizeDeps: {
exclude: ["vue-demi"],
},
plugins: [
vue(),
dts({
insertTypesEntry: true,
}),
],
server: {
open: true,
},
build: {
lib: {
entry: resolve(__dirname, "src/lib.ts"),
name: "complib",
fileName: "complib",
},
rollupOptions: {
external: ["vue"],
output: {
globals: {
vue: "Vue",
},
exports: "named",
},
},
},
});
};
The entry looks like:
import { App, install } from "vue-demi";
import TestComp from "./components/TestComp.vue";
import "./tailwind.css";
install();
export default {
install: (app: App) => {
app.component("TestComp", TestComp);
},
};
export { Header };
And here is a minimal component TestComp.vue:
<script setup lang="ts">
import { onMounted } from "vue";
onMounted(() => {
console.log(import.meta.env.VITE_TEST_VAR);
});
</script>
<template>
<span>Test Comp</span>
</template>

How to mock SVG's when snapshot testing with vitest and Storybook?

I am trying to run vitest snapshot tests on Storybook stories using the composeStories Fn from #storybook/testing-react, but I keep getting the error:
FAIL src/components/common/Nav/Nav.test.tsx > Nav Component > it should match the snapshot
Error: Element type is invalid: expected a string (for built-in components) or a class/function
(for composite components) but got: undefined. You likely forgot to export your component from
the file it's defined in, or you might have mixed up default and named imports.
Check the render method of `Nav`.
//... stack trace
I believe it's related to the svg imports, as this only occurs in components that import svgs as react components via the SVGR library. i.e.
// components/common/Nav.tsx
import { ReactComponent as ECDLogo } from '#assets/ecd_logo.svg';
And my vite.config.ts uses the vite-svgr-plugin:
// vite.config.ts
import { defineConfig } from 'vite';
import react from '#vitejs/plugin-react';
import svgr from 'vite-plugin-svgr';
import tsconfigPaths from 'vite-tsconfig-paths';
import path from 'path';
const tsConfigPathsOpts = {
extensions: ['.svg', '.png', '.jpeg'],
loose: true,
};
export default defineConfig({
build: {
outDir: 'build',
},
define: {
global: {},
},
resolve: {
alias: {
'#': path.resolve(__dirname, './src'),
'#assets': path.resolve(__dirname, './src/assets'),
'#styles': path.resolve(__dirname, './src/styles'),
'#types': path.resolve(__dirname, './src/types'),
'#components': path.resolve(__dirname, './src/components'),
},
},
plugins: [react(), svgr(), tsconfigPaths(tsConfigPathsOpts)],
});
My Storybook config (.storybook/main.js) looks like so:
const path = require('path');
const { mergeConfig } = require('vite');
const tsconfigPaths = require('vite-tsconfig-paths');
const svgr = require('vite-plugin-svgr');
const tsConfigPathsOpts = {
extensions: ['.svg', '.png', '.jpeg'],
loose: true,
};
module.exports = {
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.#(js|jsx|ts|tsx)'],
addons: [
'#storybook/addon-essentials',
'#storybook/preset-create-react-app',
'#storybook/addon-a11y',
'#storybook/node-logger',
'storybook-addon-designs',
'storybook-color-picker',
'storybook-dark-mode',
],
framework: '#storybook/react',
core: {
builder: '#storybook/builder-vite',
},
async viteFinal(config, { configType }) {
return mergeConfig(config, {
resolve: {
alias: {
'#': path.resolve(__dirname, '../src'),
'#assets': path.resolve(__dirname, '../src/assets'),
'#styles': path.resolve(__dirname, '../src/styles'),
'#types': path.resolve(__dirname, '../src/types'),
'#components': path.resolve(__dirname, '../src/components'),
},
},
plugins: [svgr(), tsconfigPaths.default(tsConfigPathsOpts)],
});
},
};
I've come to understand that I need to mock these SVG's so that their snapshot is consistent, but I need direction on whether my mocking implementation is correct. See the vi.mock Fn below.
// components/common/Nav/Nav.test.tsx
import React from 'react';
import { render } from '#testing-library/react';
import '#testing-library/jest-dom/extend-expect';
import { composeStories } from '#storybook/testing-react';
import * as stories from './Nav.stories'; // import all stories from the stories file
import { vi } from 'vitest';
const { NavDefault } = composeStories(stories);
👀
vi.mock('#assets/*', () => {
return {
default: 'SVGUrl',
ReactComponent: 'div',
};
});
describe('Nav Component', () => {
test('it should match the snapshot', () => {
const { asFragment } = render(<NavDefault />);
expect(asFragment()).toMatchSnapshot();
});
});
I was expecting this to mock all the imports from #assets/* to be strings "SVGUrl" or 'div'
But I get the same error as above:
FAIL src/components/common/Nav/Nav.test.tsx > Nav Component > it should match the snapshot
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
we had the same issue today and fixed it by adding the plugin svgr() in vitest.config.ts
import svgr from "vite-plugin-svgr";
export default defineConfig({
plugins: [
// ...other plugins
svgr(),
]
})

Using vue slots in library gives currentRenderingInstance is null

I am creating a Vue component library with Rollup, but when I use slots it gives me the following error:
Uncaught (in promise) TypeError: currentRenderingInstance is null
I made a very simple component in my library:
<script setup></script>
<template>
<button>
<slot></slot>
</button>
</template>
<style scoped></style>
Then I simply use it like this:
<ExampleComponent>
Text
</ExampleComponent>
If I remove the slot and replace it with a prop or hard-coded text, everything works fine.
This is my rollup.config.js:
import { defineConfig } from 'rollup';
import path from 'path';
import resolve from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
import postcss from 'rollup-plugin-postcss';
import vue from 'rollup-plugin-vue';
// the base configuration
const baseConfig = {
input: 'src/entry.js',
};
// plugins
const plugins = [
vue(),
resolve({
extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue'],
}),
// process only `<style module>` blocks.
postcss({
modules: {
generateScopedName: '[local]___[hash:base64:5]',
},
include: /&module=.*\.css$/,
}),
// process all `<style>` blocks except `<style module>`.
postcss({ include: /(?<!&module=.*)\.css$/ }),
commonjs(),
];
const external = ['vue'];
const globals = {
vue: 'Vue',
};
export default [
// esm
defineConfig({
...baseConfig,
input: 'src/entry.esm.js',
external,
output: {
file: 'dist/vue-my-lib.esm.js',
format: 'esm',
exports: 'named',
},
plugins,
}),
// cjs
defineConfig({
...baseConfig,
external,
output: {
compact: true,
file: 'dist/vue-my-lib.ssr.js',
format: 'cjs',
name: 'VueMyLib',
exports: 'auto',
globals,
},
plugins,
}),
// iife
defineConfig({
...baseConfig,
external,
output: {
compact: true,
file: 'dist/vue-my-lib.min.js',
format: 'iife',
name: 'VueMyLib',
exports: 'auto',
globals,
},
plugins,
}),
];
Any idea about the problem?
After a whole day of searching, I found the solution (here and here). It's a problem with using a library locally (e.g., through npm link) where it seems there are two instances of Vue at the same time (one of the project and one of the library). So, the solution is to tell the project to use specifically its own vue through webpack.
In my case, I use Jetstream + Inertia, so I edited webpack.mix.js:
const path = require('path');
// ...
mix.webpackConfig({
resolve: {
symlinks: false,
alias: {
vue: path.resolve("./node_modules/vue"),
},
},
});
Or if you used vue-cli to create your project, edit the vue.config.js:
const { defineConfig } = require("#vue/cli-service");
const path = require("path");
module.exports = defineConfig({
// ...
chainWebpack(config) {
config.resolve.symlinks(false);
config.resolve.alias.set("vue", path.resolve("./node_modules/vue"));
},
});
Thanks to #mikelplhts
On vite + esbuild I used:
export default defineConfig({
...
resolve: {
alias: [
...
{
find: 'vue',
replacement: path.resolve("./node_modules/vue"),
},
],
},
...

How to setup `vite-plugin-pages`, cannot find module `~pages`

I'm trying to set up file system based routing for a Vue 3 application using Vite with the help of vite-plugin-pages.
I created the project using yarn create vite with vue-ts as the options and added the plugin via yarn add vite-plugin-pages --dev, yarn add vue-router.
Following the readme on the github, I have added the following to my vite.config.ts:
import Pages from 'vite-plugin-pages'
export default {
plugins: [
// ...
Pages(),
],
}
However, at the next step, in main.ts:
import { createRouter } from 'vue-router'
import routes from '~pages'
const router = createRouter({
// ...
routes,
})
I cannot seem to import from ~pages. I cannot find the module. vue-router itself is working fine, as I can create a router fine, declaring the routes myself. In a vite template, they seem to be using import routes from 'virtual:generated-pages' instead and I have no idea how either works.
So, the question is, how would I go about generating the dynamic routes and as a whole, set up the usage of vite-plugin-pages?
You can try like this:
import Pages from "vite-plugin-pages"
export default defineConfig({
plugins: [
Pages({
pagesDir: [
{dir: 'src/pages', baseRoute: ''},
],
extensions: ['vue'],
syncIndex: true,
replaceSquareBrackets: true,
extendRoute(route) {
if (route.name === 'about')
route.props = route => ({query: route.query.q})
if (route.name === 'components') {
return {
...route,
beforeEnter: (route) => {
// eslint-disable-next-line no-console
// console.log(route)
},
}
}
},
}),
],
});
Then in main.js
import { createRouter, createWebHistory } from 'vue-router';
import generatedRoutes from 'virtual:generated-pages';
const router = createRouter({
history: createWebHistory(),
routes: generatedRoutes,
});
You can also declare the reference in any of your type declarations.
/// <reference types="vite-plugin-pages/client" />
// tsconfig.json
"compilerOptions": {
...
"types": ["vite-plugin-pages/client"]
}