imported apiService undefined in typescript - javascript

We are using typescript and exporting one class as following (we are using nuxt and class style component if this relates to webpack issue).
export class ApiService {
static apiHost = '/';
}
When we try to import it as following, it gives ApiService as undefined and so gives error on apiHost access as ApiService gets undefined.
import { ApiService } from '../services/api-service';
my tsconfig is as following.
{
"compilerOptions": {
"module": "commonjs",
"declaration": false,
"removeComments": true,
"noLib": false,
"allowSyntheticDefaultImports": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowJs": true,
"target": "esnext",
"resolveJsonModule": true,
"sourceMap": true,
"outDir": "./dist",
"esModuleInterop": true,
"moduleResolution": "node",
"baseUrl": "./",
"skipLibCheck": true, // TODO: Remove. Temporary. https://github.com/nuxt/typescript/issues/49
"paths": {
"~/*": ["server/*"],
"#/*": [
"client/*"
],
},
"types": [
"node",
"#types/node",
"#nuxt/vue-app",
"vuex-class-component/dist",
]
},
"include": [
"server/**/*",
"client/**/*"
],
"exclude": [
"node_modules"
]
}
my webpack.config.js
const webpack = require('webpack');
const path = require('path');
const nodeExternals = require('webpack-node-externals');
const WebpackShellPlugin = require('webpack-shell-plugin');
module.exports = {
entry: ['webpack/hot/poll?1000', './server/main.ts'],
watch: true,
target: 'node',
externals: [
nodeExternals({
allowlist: ['webpack/hot/poll?1000'],
}),
],
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
mode: 'development',
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new WebpackShellPlugin({ onBuildEnd: ['node dist/main.js'] }),
],
output: {
path: `${__dirname}/dist`,
publicPath: '/',
},
};
Command I am running
ts-node -r tsconfig-paths/register server/main.ts

Actually I didn't post entire code as I thought it wasn't necessary.
But service was also calling back the class where service was imported.
import { AuthConfig } from '../config/auth-config';
export class ApiService {
static apiHost = '/';
static mgr = new Oidc.UserManager(
new AuthConfig().IdentityServerOAuth2Config, // This was causing issue as it was causing cyclic imports.
);
}
Follwing is the code where cyclic dependency was happening.
import ApiService from '../services/api-service';
export class AuthConfig {
`${ApiService.apiHost}api/callback` // This was again calling back the apiService resulting in cyclic dependency.
}

Related

How to enable a SharedRuntime Environment in a custom function excel add-in with a separate vuejs taskpane

What I need to do:
Create a shared runtime environment so that my excel custom functions can have access to the workbook information.
Current Setup:
The way the project seems to have been set up is, using the yeoman office generator to generate a custom function addin and then using vue-cli to generate a vue app to use as the taskpane.
Folder Structure:
RootFolder
Add-In
dist
node_modules
src
config.json
manifest.xml
jest.config.js
package.json
tsconfig.json
webpack.config.js
Taskpane
dist
public
node_modules
src
assets
modules
plugins
router
store
views
App.vue
main.ts
shims-vue.d.ts
shims.tsx.d.ts
shims.vuetify.d.ts
.browserlistrc
.eslintrc.js
babel.config.js
package.json
tsconfig.json
vue.config.js
Webpack config for addin prior to changes:
module.exports = async (env, options) => {
const dev = options.mode === "development";
const buildType = dev ? "dev" : "prod";
const config = {
node: {
fs: 'empty' // https://github.com/webpack-contrib/css-loader/issues/447
},
devtool: "source-map",
entry: {
functions: "./src/functions/functions.ts",
polyfill: "#babel/polyfill",
commands: "./src/commands/commands.ts"
},
resolve: {
extensions: [".ts", ".tsx", ".html", ".js"]
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: "babel-loader"
},
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: "ts-loader"
},
{
test: /\.html$/,
exclude: /node_modules/,
use: "html-loader"
},
{
test: /\.(png|jpg|jpeg|gif)$/,
loader: "file-loader",
options: {
name: '[path][name].[ext]',
}
}
]
},
plugins: [
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: dev ? [] : ["**/*"]
}),
new CustomFunctionsMetadataPlugin({
output: "functions.json",
input: "./src/functions/functions.ts"
}),
new EnvironmentPlugin({
NODE_ENV: env.NODE_ENV || 'local'
}),
new HtmlWebpackPlugin({
filename: "functions.html",
template: "./src/functions/functions.html",
chunks: ["polyfill", "functions"]
}),
new CopyWebpackPlugin([
{
to: "[name]." + buildType + ".[ext]",
from: "manifest*.xml",
transform(content) {
if (dev) {
return content;
} else {
return content.toString().replace(new RegExp(urlDev, "g"), urlProd);
}
}
}
]),
new HtmlWebpackPlugin({
filename: "commands.html",
template: "./src/commands/commands.html",
chunks: ["polyfill", "commands"]
})
],
devServer: {
headers: {
"Access-Control-Allow-Origin": "*"
},
https: (options.https !== undefined) ? options.https : await devCerts.getHttpsServerOptions(),
port: process.env.npm_package_config_dev_server_port || 4000
}
};
return config;
};
Main.ts File:
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store/index";
import vuetify from "./plugins/vuetify";
Vue.config.productionTip = false;
/* eslint-disable-next-line #typescript-eslint/no-explicit-any */
(window as any).Office.onReady(() => {
new Vue({
router,
store,
vuetify,
render: (h) => h(App),
}).$mount("#app");
});
tsconfig.json - add-in
{
"compilerOptions": {
"allowJs": true,
"baseUrl": ".",
"esModuleInterop": true,
"experimentalDecorators": true,
"jsx": "react",
"module": "commonjs",
"noEmitOnError": true,
"outDir": "lib",
"resolveJsonModule": true,
"sourceMap": true,
"target": "es5",
"lib": [
"es2015",
"dom"
]
},
"exclude": [
"node_modules",
"dist",
"lib",
"lib-amd"
]
}
tsconfig.json - taskpane
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env",
"node"
],
"paths": {
"#/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}
The Add-In folder holds the custom functions and the Taskpane folder holds the Vuejs app. I have left out other default files and added these because I believe they will help communicate my possible issue.
Steps To Merge:
I have edited Manifest.xml following the steps provided on Microsofts documentation.
Updated name to use SharedRuntime
<Set Name="SharedRuntime" MinVersion="1.1"/>
Added Runtimes tags within the Host tag
<Runtimes>
<Runtime resid="Taskpane.Url" lifetime="long" />
</Runtimes>
Updated the Page tag to use Taskpane.Url
<Page>
<SourceLocation resid="Taskpane.Url"/>
</Page>
Updated the FunctionFile tag with Taskpane.Url
<FunctionFile resid="Taskpane.Url"/>
In webpack.config.js:
I have removed the HtmlWebpackPlugin references and replaced with the following.
new HtmlWebpackPlugin({
filename: "index.html",
template: "../taskpane/public/index.html",
chunks: ["polyfill", "taskpane", "commands", "functions"]
})
Steps I did not provided in the Documentation:
Since the project was created using the yeoman office generator with the customfunctions option selected, I believe I needed to add the following to the webpack.config.js file's entry object:
entry: {
functions: "./src/functions/functions.ts",
polyfill: "#babel/polyfill",
commands: "./src/commands/commands.ts",
taskpane: "../taskpane/src/main.ts" <----- new addition
Problem:
When I try to build the project it throws errors such as:
ERROR in ../taskpane/src/main.ts
Module build failed
Error: TypeScript emitted no output for main.ts
Module not found errors
Property doesn't exist errors
More Info:
I'm thinking (but would love to confirm) that the steps I took to create the shared runtime provided by the documentation are indeed correct, along with adding the taskpane file to the entry object in the webpack config. But I just can't figure out why it won't compile. I'm thinking it has to do with the different tsconfig.json configurations. The addin is using target: "es5" while taskpane is using target: "esnext". There are other differences as well. If somebody can help me with this and needs that information, I will be more than happy to add it.

Using SVG as React Component from Private React UI Library-(CRA) inside React app with Webpack 5 crash

I created a UI Library with CRA.
The library is published on npm.
Components in the library use SVG, which I use with the syntax of
import {ReactCompoent as Icon} from 'assets / icon'
I want to use the library inside my main app that I create with react 17.0.2 and webpack 5.
I add the loaders to Webpack and I can use svg as components inside Main app
as -
import CalendarIcon from './Calendar.svg'
and it works.
After I install the library and import the component that use SVG as ReactComponent:
import {BadgeBox} from '#privatelib/ui/lib/src'
the app crashes. With an error of:
WARNING in ./node_modules/#privatelib/ui/lib/src/components/BadgeBox/index.js 107:1697-1707
export 'ReactComponent' (imported as 'CloseIcon') was not found in '../../assets/sm/xsmall-icon.svg' (possible exports: default)
My React UI Library:
components:
import { ReactComponent as CloseIcon } from '../../assets/sm/x-small-icon.svg';
tsconfig file:
{
"compilerOptions": {
"target": "es5",
"baseUrl": "src",
"lib": [
"dom",
"dom.iterable",
"esnext",
"es5",
"es2015",
"es2016"
],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"sourceMap": true,
"declarationMap": true,
"declaration": true,
"outDir": "lib"
},
"types": ["cypress", "cypress-file-upload"],
"include": [
"src/**/*",
"custom.d.ts",
],
}
My Main App:
webpack config:
const HtmlWebPackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const deps = require('./package.json').dependencies;
module.exports = {
output: {
filename: '[name].[contenthash:20].esm.js',
chunkFilename: '[name].[chunkhash:20].esm.js',
hashFunction: 'xxhash64',
pathinfo: false,
crossOriginLoading: false,
clean: true,
publicPath: 'auto',
},
resolve: {
extensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
},
devServer: {
port: 3011,
historyApiFallback: true,
},
module: {
rules: [
{
test: /\.m?js/,
type: 'javascript/auto',
resolve: {
fullySpecified: false,
},
},
{
test: /\.(css|s[ac]ss)$/i,
use: ['style-loader', 'css-loader', 'postcss-loader'],
},
{
test: /\.(ts|tsx|js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: ['#svgr/webpack'],
},
{
test: /\.(?:ico|gif|png|jpg|jpeg|)$/i,
type: 'asset/resource',
},
{
test: /\.(woff(2)?|eot|ttf|otf|)$/,
type: 'asset/inline',
},
],
},
plugins: [
new ModuleFederationPlugin({
name: 'sidebar',
filename: 'remoteEntry.js',
remotes: {},
exposes: {
'./SideBar': './src/components/Sidebar/index.tsx',
},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
'react-dom': {
singleton: true,
requiredVersion: deps['react-dom'],
},
},
}),
new HtmlWebPackPlugin({
template: './src/index.html',
}),
],
};
babelrc:
{
"presets": ["#babel/preset-typescript", "#babel/preset-react", "#babel/preset-env"],
"plugins": [
["#babel/transform-runtime"],
"babel-plugin-styled-components"
]
}
TL;DR
The right way of importing default exports in JavaScript is
import CloseIcon from '../../assets/sm/x-small-icon.svg';
In JavaScript, the import syntax is as follows:
import defaultExport from "module-name";
import { export1 } from "module-name";
which means:
"import the component of module-name that is exported as default and use it as defaultExport"
"import the component of module-name that is exported as export1 and use it as such"
According to the SVGR docs (1),
Please note that by default, #svgr/webpack will try to export the React Component via default export if there is no other loader handling svg files with default export.
Translated to plain JavaScript-English, this means "as long as you do not tell us otherwise, we will export the ReactComponent as the default". Since you are not configuring anything different in your webpack config and trying to import the ReactComponent, I assume it should be available as the default export. Therefore, the right way to importing it is
import CloseIcon from '../../assets/sm/x-small-icon.svg';
This is just a guess, of course you can proof me wrong. (2)
I assume you are using #svgr/webpack again, as in your previous question.
Since this proposal is deducted from the docs and your code, there might be other factors involved that I'm not aware of.

`Cannot read properties of undefined` for enum after bundling with webpack

I have a React Library that I want to make buildable using Webpack. The library is written using Typescript. It seems everything is working, but for some reason enums aren't.
When I install the library into my React App, I find Cannot read properties of undefined in the browser console for the enum.
I've tried looking in the outputted bundle and it does appear that the enum is being compiled into the bundle. I feel like I must have a misconfiguration somewhere. Before I was able to bundle with microbundle-crl which we're moving from in favour of Webpack.
Here is my webpack.config.js file:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const DtsBundleWebpack = require('dts-bundle-webpack');
module.exports = {
mode: 'production',
entry: './src/index.tsx',
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
resolve: {
extensions: ['.tsx', '.ts', '.json', 'jsx', '.js'],
},
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.(ts|tsx)$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, //Extract css into files
'css-loader', // Turns css into commonjs
],
},
{
test: /\.pcss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader', // Turns css into commonjs
'postcss-loader'
]
},
],
},
plugins: [
new MiniCssExtractPlugin({ filename: 'randomcompany-components.css' }),
new DtsBundleWebpack({
name: '#randomcompany/components',
main: './dist/src/index.d.ts',
out: '../index.d.ts',
}),
],
};
My tsconfig.json is as follows:
{
"compilerOptions": {
"outDir": "dist",
"module": "esnext",
"lib": ["dom", "esnext"],
"types": ["react", "react-scripts"],
"moduleResolution": "node",
"jsx": "react",
"sourceMap": true,
"declaration": true,
"declarationDir": "dist",
"esModuleInterop": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"isolatedModules": true,
"preserveConstEnums": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true
},
"include": ["src", "src/lang"],
"exclude": ["node_modules", "dist", "src/stories"]
}
My enum is in this format:
export enum Test {
TestOne = "Test One",
TestTwo = "Test Two",
TestThree = "Test Three"
};
export default Test;
You should write it like below:
const Test = {
TestOne: "Test One",
TestTwo: "Test Two",
TestThree: "Test Three",
};
export default Test;
But in my opinion, using enum makes your bundle file a little bit heavy, just advise. use simple JavaScript objects.

Webpack - import const from .d.ts file not working - Can't resolve '#nuvolo/servicenow-types/server/GlideRecord'

I'm doing this:
import { GlideRecord } from "#nuvolo/servicenow-types/server/GlideRecord";
I have a file node_modules/#nuvolo/servicenow-types/server/GlideRecord.d.ts
It contains:
...
type GlideRecordConstructor = { new <T>(table: string): GlideRecord<T> };
type GlideRecord<T> = GlideRecordBase<T> & T;
declare const GlideRecord: GlideRecordConstructor;
export { GlideRecord };
If I run tsc it works, no errors
Webpack says:
Module not found: Error: Can't resolve '#nuvolo/servicenow-types/server/GlideRecord' in ...
Webpack config:
{
mode: "production",
//set name of record as the library name
output: {
filename: "file.js"
},
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader',
//use: 'awesome-typescript-loader',
exclude: /node_modules/,
},
],
},
resolve: {
//modules: ['node_modules'],
extensions: [ '.ts', '.js' ], // Allows imports to work from .ts and .js
},
}
tsconfig.json:
{
"transpile": false,
"compilerOptions": {
"lib": ["es2015", "dom"],
"esModuleInterop": true,
"baseUrl": ".",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true
}
}
how do I fix this?
I've also created a GH issue here: https://github.com/nuvolo/sincronia/issues/138

SCRIPT5022: SCRIPT5022: Can't resolve all parameters for ApplicationModule: (?)

I am using Angular 7 and the latest version of web pack.
Initialized Angular 7 through Angular CLI. When I tried using web pack with enabling production mode, I am getting the below error.
SCRIPT5022: SCRIPT5022: Can't resolve all parameters for ApplicationModule: (?).
Webpack.config.js
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: './src/main.ts',
module: {
rules: [
{
test: /\.ts$/,
use: ['ts-loader', 'angular2-template-loader'],
exclude: /node_modules/
},
{
test: /\.(html|css)$/,
loader: 'raw-loader'
},
]
},
resolve: {
extensions: ['.ts', '.js'],
alias: {
'#': path.resolve(__dirname, 'src/app/'),
}
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
inject: 'body'
}),
new webpack.DefinePlugin({
// global app config object
config: JSON.stringify({
apiUrl: 'http://localhost:4000'
})
})
],
optimization: {
splitChunks: {
chunks: 'all',
},
runtimeChunk: true
},
devServer: {
historyApiFallback: true
}
};
main.ts
import { enableProdMode } from '#angular/core';
import './polyfills';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
console.log(environment.production);
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
polyfill.js
import 'zone.js/dist/zone'; // Included with Angular CLI.
import 'core-js/es6/reflect';
import 'core-js/es7/reflect';
tsconfig.json
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"module": "es2015",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"importHelpers": true,
"target": "es5",
"typeRoots": [
"node_modules/#types"
],
"lib": [
"es2018",
"dom"
],
"paths": {
"#/*": [
"app/*"
]
}
}
}

Categories

Resources