Changing the input and output directory in Vite - vite

I am using Vite (https://vitejs.dev/) for a static multipage site.
This is the default project folder structure after the build command.
my-app/
├─ node_modules/
├─ dist/
│ ├─ assets/
│ ├─ index.html
├─ index.html
├─ main.js
├─ style.scss
├─ package.json
But I want to make this a multipage site and change the input and output directory for a better organizable way like this
my-app/
├─ node_modules/
├─ package.json
├─ src/
│ ├─ about.html
│ ├─ index.html
│ ├─ main.js
│ ├─ style.scss
├─ dist/
│ ├─ assets/
│ ├─ about.html
│ ├─ index.html
Basically, it should take the src as an input folder and output dist as a child of the my-app. When I try to do this it shows errors, then I change the scripts of the package.json into this
"scripts": {
"dev": "vite src",
"build": "vite build src",
"serve": "vite preview"
},
This way the devcommand works fine. But the 'build' command makes the dist folder inside the src folder and does not generate other HTML files except index.html.
Now how can I fix this? Any suggestion?

Create a vite.config.js file and define your project root and output directory as such:
module.exports = {
root: 'src',
build: {
outDir: '../dist'
}
}
For more info, checkout config.

For multipage apps you need to specify each entry point.
To dynamically specify all .html files in src/ directory as the entry points you can set up your vite.config.js like this:
import path from "path";
import glob from "glob";
export default {
root: path.join(__dirname, "src"),
build: {
outDir: path.join(__dirname, "dist"),
rollupOptions: {
input: glob.sync(path.resolve(__dirname, "src", "*.html")),
},
},
};
Make sure to install glob like this
npm install glob -D

If you want to use defineConfig in your vite.config.ts you can use it like this:
import { defineConfig } from 'vite'
import reactRefresh from '#vitejs/plugin-react-refresh'
import eslintPlugin from 'vite-plugin-eslint'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [reactRefresh(), eslintPlugin({ cache: false })],
root: 'src',
build: {
outDir: '../dist'
}
})

Make sure you add vite.config.js inside your Vite root directory (src).
module.exports = defineConfig({
base: '',
root: 'src',
build: {
outDir: '../dist'
}
});
Don't forget to update your package scripts. You'll need to add the --emptyOutDir flag if you want the same behavior as in the default project structure (clear output folder before building).
"scripts": {
"dev": "vite src",
"build": "vite build src --emptyOutDir",
}

You can set up your vite.config.js like this:
import path from 'path'
export default {
root: path.resolve(__dirname, 'src'),
build: {
outDir: path.resolve(__dirname, 'dist'),
rollupOptions: {
input: {
index: path.resolve(__dirname, 'src/index.html'),
about: path.resolve(__dirname, 'src/about.html')
}
}
}
}

Related

Jest with typescript + lambda functions + lambda layers (AWS)

I have an issue with importing modules for my jest tests in a setup containing lambdas, lambda layers and tests. The file structure is as following:
backend/
├─ jest.config.js
├─ package.json
├─ babel.config.js
├─ layers/
│ ├─ tsconfig.json
│ ├─ aws_handler/
├─ lambdas/
│ ├─ tsconfig.json
│ ├─ some_lambda/
│ │ ├─ index.ts
├─ tests/
│ ├─ tsconfig.json
│ ├─ some_lambda.test.ts
When I run npm test I get the following error: Cannot find module '#libs/aws' or its corresponding type declarations.
So, when I don't test it works. In lambdas/some_lambda/index.ts I import a layer the following way:
import { lambda } from '#libs/aws';
and in the lambdas/tsconfig.json I specify the relative path to the layer
"baseUrl": "",
"paths": {
"#libs/aws": [
"../lambda_layers/aws_handler"
],
}
So, when running the lambda it can find the #libs/aws module but not when testing. Ok, so far so "good".
Somewhere in jest.config.js and/or package.json I need to specify where to find this module, but I struggle doing so. Can the jest.config.js somehow inherit or look at the lambdas/tsconfig.json file?
For example I read somewhere that adding this to package.json would help
"jest": {
...
"rootDir": "./",
"modulePaths": [
"<rootDir>"
],
...
}
}
or in jest.config.js I should specify moduleDirectories etc. Does anyone have a similar setup that can tell me how to approach this?
You have to config moduleNameMapper for jest the same as what you did at tsconfig.js paths.
If you use ts-jest as a transformer, use their helper.
jest.config.js
const { pathsToModuleNameMapper } = require('ts-jest');
const { compilerOptions } = require('./lambdas/tsconfig');
module.exports = {
// [...]
modulePaths: [compilerOptions.baseUrl],
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths),
}
...
Or you can do it without a helper:
moduleNameMapper: {
'^#libs/aws/(.*)$': '<rootDir>/lambda_layers/aws_handler/$1'
},

Express & Typescript - Importing local modules with multiple ts-configs

I'm modularising my code to split my oauth routes into a seperate typescript file in a sibling folder. I'm not sure what I'm doing wrong when trying to import from a seperate folder. On ts-node run its unable to find the authRoutes.ts.
My set up is have 3 seperate ts-configs, one is in the root of the workplace which has all the main settings I need whilst I have 2 seperate ts-config files in the /src/routes and /src/ts folder that extends from the root with the only difference being the outDirs in each of the 2.
I've tried setting up the /src/routes path as a "path:" setting in the root ts-config with the same error when trying to run ts-node. Below is my folder structure and my root ts-config both other ts-config file uses to extend.
import authRoutes from "../routes/authRoutes";
app/
├─ public/
│ ├─ css/
│ ├─ js/
│ ├─ routes/
├─ src/
│ ├─ routes/
│ │ ├─ tsconfig.json
│ │ ├─ authRoute.ts
│ ├─ scss/
│ ├─ ts/
│ │ ├─ tsconfig.json
│ │ ├─ app.ts
├─ views/
tsconfig.json
{
"include": ["src/**/*"],
"compilerOptions": {
"target": "es2022",
"module": "es2022",
"composite": true,
"moduleResolution": "node",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
},
"ts-node": {
"esm": true
},
"references": [
{ "path": "./src/ts/tsconfig.json" },
{ "path": "./src/routes/tsconfig.json" }
]
}

How do I export a TypeScript ESM Module as an NPM package?

Recently, I had to fork an open source NPM package that was built using TypeScript and exported using CommonJS. The package hasn't been maintained for a couple of years, so I had to update all of the dependencies, which made the code break.
One of the dependencies, unified, was being imported using const unified = require("unified"); which is CommonJS syntax, but in a newer version of unified that I updated to, they started forcing unified to be imported using ESM syntax like import { unified } from "unified". So I decided to convert my entire package to ESM.
I added "type": "module" to my package.json and updated all of the code to use ESM style imports/exports, but now that I'm ready to publish the package, I'm confused on a couple of things.
The original developer had the project setup like this:
├── src/
│ ├── index.ts
│ ├── options.ts
│ ├── toc.ts // where most of the code logic lives. This is the entry point to the application and the main function I want to export
│ └── ... // whole bunch of other typescript files
├── lib/
│ ├── index.d.ts
│ ├── index.js
│ ├── index.js.map
│ └── ... // this repeats for every typescript file in src/
├── dist/
│ ├── index.d.ts
│ ├── index.js
└── └── package.json
In tsconfig.json, he had "outDir": "lib", so all of the TypeScript files inside src/ get exported with their type stuff to the lib folder. That makes sense to me.
But what I'm confused on is what am I supposed to put in src/index.ts, dist/index.js and index.d.ts ?
This what the developer originally had:
src/index.ts
import { toc } from "./my-package";
export { CssClasses, Options } from "./options";
export * from "./types";
export { toc };
// Export `toc` as the default export
export default toc;
if (typeof module === "object" && typeof module.exports === "object") {
module.exports = Object.assign(module.exports.default, module.exports);
}
dist/index.d.ts
import toc from "#username/my-package";
export * from "#username/my-package";
export default toc;
dist/index.js
"use strict";
module.exports = require("#username/my-package");
dist/package.json
"name": "#username/my-package",
"version": "3.0.0",
// ...
"main": "index.js",
"types": "index.d.ts",
"files": [
"index.js",
"index.d.ts"
],
"engines": {
"node": ">=14"
},
"dependencies": {
"#username/my-package": "3.0.0"
}
So my questions are:
What goes inside dist/index.js and dist/index.d.ts ? Do I just make a copy of those files from lib and paste them in dist?
To make my package fully ESM, What should I replace the module.exports lines with in src/index.ts and dist/index.js ?
Is there anything else I need to add to my dist/package.json, besides "type": "module"? Is it really that simple, that I only need 3 files in my distribution folder?

Typescript builds files with incorrect path in monorepo

I have an example monorepo with 3 packages: back, front and shared. With the following folder structure:
root
├── back
│ ├── dist
│ ├── src
│ ├── test.ts
│ ├── package.json
│ └── tsconfig.json
├── front
├── shared
│ ├── dist
│ ├── src
│ ├── my-enum.ts
│ ├── package.json
│ └── tsconfig.json
├── package.json
└── tsconfig.json
test.ts
import { MyEnum } from '#test/shared/src/my-enum'
setTimeout(() => console.log(2 == MyEnum.B), 1000, 1)
my-enum.ts
export enum MyEnum{ A = 1, B, C }
When I build the back package typescript generates in the dist folder a test.js file with var my_enum_1 = require("#test/shared/src/my-enum");, however the compiled files of the shared package are in the dist folder, not in src, so if I try to run with node I get the following error:
Error: Qualified path resolution failed: we looked for the following paths, but none could be accessed.
Source path: E:\Repository\workspace_test\shared\src\my-enum
Not found: E:\Repository\workspace_test\shared\src\my-enum
Not found: E:\Repository\workspace_test\shared\src\my-enum.js
Not found: E:\Repository\workspace_test\shared\src\my-enum.json
Not found: E:\Repository\workspace_test\shared\src\my-enum.node
If I use ts-node instead of node it works, but that's not how I'd like to run this after deploy. I assume there's something I need to change in my tsconfig.json files but I can't find out what it is, other related SO questions I could find weren't very helpful.
I uploaded an example repo on github to make things easier to anyone willing to help, but here are my ts.config files:
Root:
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"sourceMap": true
}
}
Back:
{
"extends": "../tsconfig.json",
"compilerOptions": {
"composite": true,
"outDir": "dist",
"rootDir": "src"
},
"references": [
{ "path": "../shared" }
]
}
Shared:
{
"extends": "../tsconfig.json",
"compilerOptions": {
"composite": true,
"outDir": "dist",
"rootDir": "src"
}
}
Ok, so to fix this I had to change the package.json instead of the tsconfig.json. Making the main field in shared/package-json point to the dist folder doesn't do anything for some reason, but the exports field actually works, so creating an alias there solved the issue.
So for this example project it would be something like "exports": { "./src/my-enum": "./dist/src/my-enum.js" }.

How do I correctly require and declare node library typings in TypeScript?

I am trying to write a package for node in TypeScript that uses standard node libraries, for example fs, path, stream, http, and so on.
When I try to import libraries in a .ts file, VS Code marks the corresponding line with an error:
[ts] Cannot find module 'fs'.
This happens no matter how I try to import the library:
import * as fs from 'fs'; // [ts] Cannot find module 'fs'
import fs = require('fs'); // [ts] Cannot find module 'fs'
const fs = require('fs'); // [ts] Cannot find name 'require'
I (should) have the correct definitions installed with typings install --save --ambient node.
When I compile to JavaScript (using gulp and gulp-typescript, not tsc), the compliation works and the syntax highlighting shows no errors until I type in 1 character again:
How can I correctly define the node libraries for TypeScript?
I use VS Code for code highlighting and autocompletion, gulp & gulp-typescript to compile and typings for the typescript library declarations.
The project's directory structure:
├─ build/
│ └─ (output files)
├─ src/
│ └─ myfile.ts
├─ typings/
│ ├─ browser/
│ │ └─ ambient/
│ │ └─ node/
│ │ └─ index.d.ts
│ ├─ main/
│ │ └─ ambient/
│ │ └─ node/
│ │ └─ index.d.ts
│ ├─ browser.d.ts
│ └─ main.d.ts
├─ gulpfile.js
├─ package.json
├─ tsconfig.json
└─ typings.json
My tsconfig.json:
{
"compileOnSave": false,
"compilerOptions": {
"declaration": true,
"module": "system",
"moduleResolution": "node",
"noEmitOnError": true,
"noImplicitAny": true,
"target": "es5"
},
"exclude": [
"node_modules",
"typings/browser",
"typings/browser.d.ts"
]
}
My typings.json:
{
"ambientDependencies": {
"node": "registry:dt/node#4.0.0+20160412142033"
}
}
And my gulp task:
gulp.task('build-typescript', () => {
const gulpts = require('gulp-typescript');
const tsProject = gulpts.createProject('tsconfig.json', {
typescript: require('typescript'),
outFile: 'mylibrary.js',
noLib: true
});
let tsstream = (
gulp.src([
'node_modules/typescript/lib/lib.es6.d.ts',
'typings/main.d.ts',
'src/sharpscript.ts'])
.pipe(sourcemaps.init())
.pipe(gulpts(tsProject))
);
return require('merge2')(
tsstream.dts.pipe(gulp.dest('build')),
tsstream.js
.pipe(sourcemaps.write('.', { includeContent: true }))
.pipe(gulp.dest('build'))
);
});
In case anyone has experienced the same problem, I am thankful for any insights.
the installation of type declarations with 'typings install ...' is obsolete since a few months. The new way is to install it directly via npm and the #types namespace. to install the node type declarations just use npm install #types/node --save-dev.

Resources