How to include imported class in bundle, when not directly used - javascript

I'm writing my own JSX pragma and it does work pretty well except now when tying to introduce typescript JSX will not work for me. My class is being tree-shaken out or something, unless it is actively being used within a module, eg in a log statement:
/** #jsx V.create */
/** #jsxFrag V.Fragment */
import V, { render } from "#V"; // `#V` is in a webpack resolve.alias
render(document.getElementById("app"), <h1>hi</h1>);
external "V":1 Uncaught ReferenceError: V is not defined
But,
/** #jsx V.create */
/** #jsxFrag V.Fragment */
import V, { render } from "#V"; // `#V` is in a webpack resolve.alias
console.log({ V })
render(document.getElementById("app"), <h1>hi</h1>);
^^ Works!
Relevant webpack object:
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
tsconfig.json
{
"include": ["src/**/*"],
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": true,
"module": "commonjs",
"target": "esnext",
"jsx": "react",
"declaration": true,
"sourceMap": true
},
"baseUrl": "src",
"paths": {
"#V": ["js/V/index.ts"]
}
}
How can I ensure Webpack/Typescript will not remove this import?

You need to disable tree shacking for the module V.
You can use sideEffects array to disable tree shaking
Here the documentation of WebPack
In your package.json file
{
"name": "your-project",
"sideEffects": [
"./src/some-side-effectful-file.js"
]
}

Related

Jest (typescript): SyntaxError: Unexpected token 'export' (lowdb)

As the title suggests, I am having trouble with jest not allowing an export from the lowdb package within my tests. It seems to only throw this error for this single package -- the rest of my code is also using ES6 exports and my package.json file has the key type: module.
What have I tried
Adding type module -- Jest: SyntaxError: Unexpected token 'export'
Adding transformIgnorePatterns: ["<rootDir>/node_modules/(?!lowdb)"] -- Jest setup "SyntaxError: Unexpected token export"
Add a transform for js which uses babel-jest -- Jest encountered an unexpected token - SyntaxError: Unexpected token 'export'
Update my tsconfig to output commonJS modules
Update my tsconfig to allowJs:true and update my jest transforms to parse JS with ts-jest
I'm not sure where I am going wrong and am sorry in advance if I am being dim.
This is my TS Config
{
"compilerOptions": {
"rootDir": "src",
"outDir": "dist",
"esModuleInterop": true,
"allowJs": true,
"target": "ES6",
"moduleResolution": "node",
"resolveJsonModule": true,
"module": "ES6",
"baseUrl": "src",
"declaration": true,
"allowSyntheticDefaultImports": true,
"paths": {
"#services/*": ["services/*"],
"#constants/*": ["constants/*"],
"#typeDefs/*": ["typeDefs/*"],
"#config/*": ["config/*"],
"#utils/*": ["utils/*"],
"#assets/*": ["assets/*"]
}
},
"include": ["src/**/*.ts"],
"exclude": ["rollup.config.ts", "jest.config.ts"]
}
And this is my jest.config.ts file:
import type { Config } from "#jest/types";
import { pathsToModuleNameMapper } from "ts-jest";
import { compilerOptions } from "./tsconfig.json";
// Sync object
const config: Config.InitialOptions = {
verbose: true,
roots: ["<rootDir>"],
preset: "ts-jest",
testEnvironment: "node",
transform: {
"^.+\\.ts$": "ts-jest",
"^.+\\.js$": "babel-jest",
},
testRegex: ["^.+\\.test\\.ts$"],
moduleDirectories: ["src", "node_modules"],
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths),
};
export default config;
Finally, I am invoking jest as follows:
"test:ts": "jest --config=jest.config.ts",
Thank you in advance.
EDIT: Some additional context
I am pretty sure it should not affect this issue but I figure it could help to provide more context. I am running jest with two different configs -- one for JS and one for TS and the repo to which it relates has some build scripts written in JS that will only ever be run in nodeJS.
The JS config is as follows (has no issues):
// Sync object
/** #type {import('#jest/types').Config.InitialOptions} */
const config = {
verbose: true,
testEnvironment: "jest-environment-node",
transformIgnorePatterns: ["/node_modules/"],
transform: {},
testRegex: ["^.+\\.test\\.js$"],
};
export default config;
And it is invoked as follows:
"test:js": "yarn node --experimental-vm-modules $(yarn bin jest) --config=jest.config.js",
I too ran into similar issue. Here is how I fixed by tweaking jest.config.js:
module.exports = {
preset: "ts-jest",
testEnvironment: "node",
transformIgnorePatterns: ["/node_modules/(?!lowdb|steno)"],
transform: {
"^.+\\.(js)?$": require.resolve("babel-jest"),
},
};
We want the babel-jest to parse the js files, and the lowDB and one of its dependency -steno.
Next, we need to ensure the babel.config.js to contain the following (we need to configure babel with #babel/plugin-transform-modules-commonjs plugin to correctly parse import/exports and should use importInterop:'node'.
module.exports = {
env: {
test: {
presets: [
[
"#babel/preset-env",
{
targets: {
node: "current",
},
modules: "commonjs",
},
],
],
plugins: [
[
"#babel/plugin-transform-modules-commonjs",
{
importInterop: "node",
},
],
],
},
},
};
Ensure you have installed all necessary dev dependencies:
npm i -D babel-jest #babel/core
npm i -D #babel/preset-env
npm i -D #babel/plugin-transform-modules-commonjs

jsconfig path alias is not working Sveltekit

I am using svelte kit (with typescript) and have some created some shortlinks and cannot get the new link "$base" to work. I added the shortlink here
./jsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"baseUrl": ".",
"paths": {
"$lib": ["src/lib"],
"$lib/*": ["src/lib/*"],
"$base": ["src/baseApp"],
"$base/*":["src/baseApp/*"]
}
},
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"]
}
The is also no intellisense
More details about jsconfig.json here
I also found something about a similar issue with NEXT here
I tried this and it didn't work
In addition to jsconfig.json I tried adding my the paths to my tsconfig.json file also
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true
},
"paths": {
"$lib": ["src/lib"],
"$lib/*": ["src/lib/*"],
"Base": ["src/baseApp"],
"Base/*":["src/baseApp/*"]
}
}
Try adding your paths to the svelte.config.js file in the root of your project
...
import path from 'path';
/** #type {import('#sveltejs/kit').Config} */
const config = {
...
kit: {
...
vite: {
resolve: {
alias: {
$lib: path.resolve('./src/lib'),
$base: path.resolve('./src/baseApp'),
}
}
}
}
};
export default config;
Edit: Newer versions of sveltekit uses vite.config.js instead
import { sveltekit } from '#sveltejs/kit/vite';
import path from "path"
const config = {
resolve: {
alias: {
'$lib': path.resolve('./src/lib/'),
'$base': path.resolve('./src/baseApp'),
},
},
plugins: [sveltekit()]
};
export default config;
This is the latest way of implementing it. No need for vite config file
https://kit.svelte.dev/docs/configuration#alias
//svelte.config.js
import path from 'path';
const config = {
...
kit: {
...
alias: {
$components: path.resolve('./src/components')
}
}
};

How to import a self-made module in create-react-app?

I'm using create-react-app in my ReactJS app with TypeScript, and I would like to import a TypeScript/JavaScript module that I created in another project.
The module consists of a file mymodule.js, in which the code looks approximately like this:
var mymodule;
(function (mymodule) {
var MyClass = /** #class */ (function () {
function MyClass() {
}
MyClass.myMethod = function () {
// code
};
return MyClass;
}());
mymodule.MyClass = MyClass;
})(mymodule || (mymodule = {}));
Then there is the type definition file mymodule.d.ts, which looks like this:
declare module mymodule {
class MyClass {
private static myMethod;
}
}
In my create-react-app project, I placed these two files in the folder /src/vendor, and I want to use the module like this:
import { MyClass } from '../vendor/mymodule';
...
However, Visual Studio Code (i.e. the TypeScript compiler) says
File '.../vendor/mymodule.d.ts' is not a module. ts(2306)
When I run the project, the variables from the module (e.g. the class MyClass) are undefined.
This might be the reason for the error: The library is generated using module: "AMD", but create-react-app seems to enforce module: "esnext".
Edit: Here's the tsconfig.json of the create-react-app project:
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"jsx": "react",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true
},
"include": [
"src"
]
}
You can't import the file due to the fact that you are not exporting the module. In order for module loading to work, you should have an export at the bottom of your myModule class file.
export {
mymodule
}

How do I configure absolute paths for imports in TypeScript based React Native apps?

In order to avoid '../../../../' style relative imports in a TypeScript based React Native app, I would like to configure the app so that I can use absolute imports instead.
It is important that the configuration also supports Jest unit tests.
I created the app using npx react-native init MyTestApp --template typescript
React Native version: 0.60.5
What is the exact configuration I would need to achieve this?
Requirement
// Meh
import config from '../../../../../../../config';
// Awesome!
import config from '#cuteapp/config';
How To
Add this babel plugin package
yarn add --dev babel-plugin-module-resolver
My babel.config.js
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
require.resolve('babel-plugin-module-resolver'),
{
cwd: 'babelrc',
extensions: ['.ts', '.tsx', '.js', '.ios.js', '.android.js'],
alias: {
'#cuteapp': './app'
}
}
],
'jest-hoist'
]
};
My tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"isolatedModules": true,
"jsx": "react",
"lib": ["es2015", "es2015.promise", "es2016.array.include", "dom"],
"strict": true,
"moduleResolution": "node",
"baseUrl": "./",
"paths": {
"#cuteapp/*": ["app/*/index", "app/*"]
},
"noEmit": true,
"resolveJsonModule": true,
"target": "esnext",
"types": ["jest"]
},
"exclude": ["node_modules", "babel.config.js", "metro.config.js"]
}
Restart the IDE.
That's it.
Summary:
The npm package babel-plugin-module-resolver is needed, as well as some configuration in tsconfig.json and babel.config.js
Step by step:
Install babel-plugin-module-resolver using npm or yarn.
npm i babel-plugin-module-resolver --save-dev
# Or (If you're using yarn):
yarn add --dev babel-plugin-module-resolver
tsconfig.json: Add "baseUrl": "." to compilerOptions
babel.config.js: Add a key named plugins with the following value:
[
[
'module-resolver',
{
extensions: [
'.js',
'.jsx',
'.ts',
'.tsx',
'.android.js',
'.android.tsx',
'.ios.js',
'.ios.tsx'
],
root: ['.']
}
]
]
Complete configuration:
tsconfig.json:
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"isolatedModules": true,
"jsx": "react",
"lib": ["es6"],
"moduleResolution": "node",
"noEmit": true,
"strict": true,
"target": "esnext",
"baseUrl": "."
},
"exclude": ["node_modules", "babel.config.js", "metro.config.js", "jest.config.js"]
}
babel.config.js:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'module-resolver',
{
extensions: [
'.js',
'.jsx',
'.ts',
'.tsx',
'.android.js',
'.android.tsx',
'.ios.js',
'.ios.tsx'
],
root: ['.']
}
]
]
};
This is for a clean new project created using npx react-native init MyTestApp --template typescript on React Native version 0.60.5
If you do not want to use the babel plugin
create a new package.json file inside the src folder with the following. (change myapp to whatever you want to, it can even be src.)
{
"name": "myapp"
}
update your tsconfig.json file
{
"compilerOptions": {
...
"baseUrl": "./",
"paths": {
"myapp/*": ["src/*"]
}
...
}
}
In your.tsx file
import { MyThing } from 'myapp/MyThing';
For anyone who uses TypeScript and just wants to use import with absolute paths without aliases.
Assuming all of your code folders are inside of src.
Insert "baseUrl": "src" in compilerOptions object inside tsconfig.json.
Now you can use absolute paths in imports.
2022 Update
1.Create a package.json in your src folder.And add {"name":"src"} in it.
2.Update your tsconfig.json file like this,
{
"compilerOptions": {
...
"baseUrl": "./",
"paths": {
"src/*": ["src/*"]
}
...
}
}
3.Restart your ide.
Now you can import like this,
import MyComponent from 'src/components/MyComponent';
All of the other answers didn't work for me with a freshly created React Native + Typescript project.
What worked for me was setting both baseUrl and paths in tsconfig.json:
{
"baseUrl": ".",
"paths": {
"NAME_IN_PACKAGE_JSON/*": ["./*"]
}
}
Replace NAME_IN_PACKAGE_JSON with your package.json's name field.
E.g. if the name field is myapp you can do:
import HomeScreen from "myapp/screens/HomeScreen";
All you have to do if you have a "src" file on your project root is to add a package.json file in it and write { "name": "src" } in it. Then every import named "src/..." resolves beautifully.
I found this solution in this video.
You can solve it using 5 simple steps withou eject:
Step 1: Adding react-app-rewired into your devDependencies.
yarn add -D react-app-rewired or npm intall react-app-rewired --save-dev
Step 2: After installation, you'll be able to change package.json default ReactsJS scripts to:
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject"
}
Step 3: Creates a new file called tsconfig.paths.json on root path, with content like:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"services/*": ["./src/shared/services/*"],
"interfaces/*": ["./src/shared/interfaces/*"]
}
}
}
Tip 1: you can choose which path you want to use, like:
#services, #interface, #src, ~, #, etc just by changing the keys inside "paths": {}
The same is applied to it's value: ["src/shared/services/"], ["src/shared/interfaces/"], ["src/*"], use the relative path here.
Step 4: Into tsconfig.json, before "compilerOptions" you need to extends the tsconfig.paths.json you just created.
Like this:
{
"extends": "./tsconfig.paths.json",
...//rest of file infos compilerOptions, include... whatever
}
Step 5: Creates a new file config-overrides.js, adding your alias and relative paths on it:
const path = require('path');
module.exports = function override(config) {
config.resolve = {
...config.resolve,
alias: {
...config.alias,
'services': path.resolve(__dirname, 'src/shared/services'),
'interfaces': path.resolve(__dirname, 'src/shared/interfaces')
},
};
return config;
};
Tip 2: If you're using eslint, remember to have an .eslintignore file and add config-overrides.js within it.
Restart your IDE or text editor, in my case VSCode.
It's DONE!. Now just run yarn start or npm run start

Typescript shared path, unable to export const

I'm working on a project where the front-end and the back-end reside in the same directory and both use TypeScript.
I am using a shared path to store some interfaces and constants between the two projects.
But, when I try to export a constant from any file in /shared, I get a :
Error: Cannot find module '#shared/test'
server-config.ts:
"compilerOptions": {
"baseUrl": "./src/server/",
"sourceMap": false,
"module": "commonjs",
"moduleResolution": "node",
"target": "ES2017",
"types": ["node"],
"outDir": "./dist/",
"allowJs": true,
"typeRoots": [
"node_modules/#types"
],
"paths": {
"#shared/*": ["../shared/*"]
},
/shared/test.ts:
// If I remove the following line, no compile error, even finds TheTest
export const TEST = 'test';
export class TheTest {
}
import
// << Module not found (only if I import TEST)
import { TEST, TheTest } from '#shared/test';
export function Foo() {
console.log(TEST);
}

Categories

Resources