typescript - Importera från underkataloger för ett javascript-paket
Jag har ett TypeScript-bibliotek som består av flera mappar. Varje mapp innehåller en index.ts-fil som exporterar viss affärslogik. Jag försöker paketera detta med Rollup för att uppnå detta beteende på anropsplatsen:
import { Button, ButtonProps } from 'my-lib/button'
import { Input, Textarea } from 'my-lib/input'
import { Row, Column } from 'my-lib/grid'
Detta är katalogstrukturen:
Jag har en huvud-index.ts under src/ som innehåller:
export * from './button';
export * from './input';
export * from './grid';
Med den här stilen kan jag göra:
import { Button, Input, InputProps, Row, Column } from 'my-lib'
Men jag vill inte ha detta. Jag vill ha åtkomst till varje modul via deras namespace. Om jag tar bort exports från index.ts-filen, är allt jag kan göra:
import { Button } from 'my-lib/dist/button'
vilket är något jag inte såg tidigare. Att lägga till dist/ i importuttalandet betyder att jag får åtkomst till modulerna via en relativ sökväg. Jag vill ha my-lib/Button.
Jag använder rollup. Jag försökte använda alias-plugin men det fungerade inte. Nedan är min rollup-konfiguration:
const customResolver = resolve({
extensions: ['ts'],
});
export default {
input: `src/index.ts`,
output: [
{
file: pkg.main,
format: 'cjs',
sourcemap: true,
// plugins: [terser()],
},
{
file: pkg.module,
format: 'es',
sourcemap: true,
plugins: [terser()],
},
],
// Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash')
external: [],
watch: {
include: 'src/**',
},
plugins: [
// Allow json resolution
json(),
// Compile TypeScript files
typescript({ useTsconfigDeclarationDir: true }),
// Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
commonjs(),
// Allow node_modules resolution, so you can use 'external' to control
// which external modules to include in the bundle
// https://github.com/rollup/rollup-plugin-node-resolve#usage
resolve(),
// Resolve source maps to the original source
sourceMaps(),
alias({
entries: [
{ find: 'my-lib/button', replacement: './dist/button' },
{ find: 'my-lib/input', replacement: './dist/input' },
{ find: 'my-lib/grid', replacement: './dist/grid' },
],
customResolver,
}),
],
};
Och detta är tsconfig-filen:
{
"compilerOptions": {
"target": "es5",
"module": "ES6",
"lib": ["ES2017", "ES7", "ES6", "DOM"],
"declaration": true,
"declarationDir": "dist",
"outDir": "dist",
"sourceMap": true,
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"allowJs": false,
"moduleResolution": "node",
"resolveJsonModule": true,
"baseUrl": "./src",
"paths": {
"my-lib/button": ["./src/button"],
"my-lib/input": ["./src/input"],
"my-lib/grid": ["./src/grid"]
}
},
"exclude": ["node_modules", "dist", "**/*.test.ts"],
"include": ["src/**/*.ts"]
}
Jag vet inte hur man uppnår samma struktur som lodash/xxx eller material-ui/yyy med rollup.
Folk föreslår alias eller namngivna exporter men jag kunde inte få det att fungera.
Det närmaste till mitt problem är frågan nedan:
Importera från undermapp i npm-paket
Jag vill uppnå samma sak men med typescript och rollup.
Jag tror att jag missar något, tack.
Svar #1
Detta är möjligt, men kräver några extra steg. Som nämnts ovan, är detta tillvägagångssättet som används av Material-UI.
Tricket är att publicera en kuraterad dist-mapp, snarare än rotmappen i ditt repo.
Byggnad
För att börja med, låt oss bara vara tydliga med att det inte spelar någon roll om ditt bibliotek är byggt med CommonJS eller ESM. Detta handlar om modulupplösning.
Låt oss anta att projektet heter my-package.
Nu kommer de flesta projekt, efter att vi har byggt src/ till dist/, att ha
my-package
package.json
src/
index.js
dist/
index.js
och i package.json
"main": "dist/index.js"
eller för esm
"module": "dist/index.js"
Publicering
De flesta projekt lägger bara till .npmignore och publicerar projektets rot, så när det installeras hamnar projektet i node_modules på följande sätt:
node_modules
my-package/
package.json
dist/
index.js
Löser
När det är installerat, överväg denna import:
import myProject from "my-project";
Modulupplösaren kommer att göra detta (ganska förenklat, eftersom hela algoritmen är irrelevant här):
- Gå till
node_modules - Hitta
my-project - Ladda
package.json - Returnera filen i
mainellermodule
Vilket kommer att fungera eftersom vi har
node_modules
my-package/
package.json
dist/
index.js
Lösa delvägar
import something from "my-project/something";
Upplösningsalgoritmen kommer att fungera med
node_modules
my-project/
somthing.js
också med
node_modules
my-project/
something/
index.js
och med
node_modules
my-project/
something/
package.json
där det i det senare fallet återigen kommer att titta på main eller module.
Men vi har:
node_modules
my-package/
package.json
dist/
index.js
Tricket
Tricket är, istället för att publicera din projektrot med sin dist-mapp, att "franka" dist-mappen och publicera dist-mappen med npm publish dist istället.
Frank (som i frank a letter) betyder att du behöver skapa en package.json i din dist-mapp; lägg till README.md LICENSE osv.
Ett ganska kort exempel på hur detta görs kan hittas här.
Så, med tanke på att vi hade efter byggandet:
node_modules
my-package/
package.json
dist/
index.js
something.js
När det väl publicerats får vi
node_modules
my-project/
package.json
index.js
something.js
Där package.json är den noggrant utvalda.
Svar #2
För det första är den enda skillnaden mellan
import { Button } from 'my-lib/dist/button'
och
import { Button } from 'my-lib/button'
är bara ett ytterligare katalognivå.
När det är sagt, tills du har "outDir": "dist", i din tsconfig.json-fil behöver du lägga till dist/ i dina import-satser.
Faktiskt, båda de bibliotek du tagit som exempel distribueras med filer i rotkatalogen: lodash har direkt js-filer i roten, medan material-ui inte har något outDir-alternativ i sin tsconfig.json-fil (vilket betyder att skriva ut filer till rotkatalogen).
Hoppas det här hjälper.
