Escuchar a @nycdotnet me ha
La propuesta aquí se inició por primera vez en tiempos prehistóricos (incluso antes del n. ° 11), cuando los dinosaurios caminaban por la tierra quemada. Si bien nada en esta propuesta es novedoso, en sí mismo, creo que es hora de que abordemos el tema. La propia propuesta de Steve es la # 3394.
Actualmente, en TypeScript, es bastante fácil comenzar y ponerse en marcha, y lo hacemos más fácil cada día (con la ayuda de cosas como # 2338 y el trabajo en System.js). Esto es maravilloso. Pero hay un pequeño obstáculo a medida que crece el tamaño del proyecto. Actualmente tenemos un modelo mental que es algo como esto:
Para proyectos de pequeño tamaño, tsconfig.json le brinda una forma fácil de configurar para comenzar con cualquiera de los editores de una manera multiplataforma. Para proyectos a gran escala, es probable que termine cambiando a sistemas de compilación debido a los variados requisitos de los proyectos a gran escala, y el resultado final será algo que funcione para sus escenarios, pero es difícil de configurar porque es demasiado difícil de configurar. la variedad de sistemas y opciones de construcción.
Steve, en su entrevista, señala que este no es el modelo correcto del mundo y yo tiendo a estar de acuerdo con él. En cambio, hay tres tamaños de proyecto:
A medida que escala el tamaño del proyecto, argumenta Steve, debe poder escalar a través del paso medio, o el soporte de la herramienta se cae demasiado rápido.
Para solucionar esto, propongo que apoyemos proyectos "medianos". Estos proyectos tienen pasos de compilación estándar que podrían describirse en tsconfig.json hoy, con la excepción de que el proyecto se compila a partir de varios componentes. La hipótesis aquí es que hay bastantes proyectos a este nivel que podrían beneficiarse de este apoyo.
Proporcione una experiencia fácil de usar para los desarrolladores que crean proyectos de "tamaño mediano" tanto para la compilación de la línea de comandos como cuando trabajan con estos proyectos en un IDE.
Esta propuesta _no_ incluye la compilación opcional, ni ningún paso fuera de lo que el compilador maneja hoy. Esta propuesta tampoco cubre el empaquetado o empaquetado, que se manejarán en una propuesta separada. En resumen, como se menciona en el nombre, esta propuesta cubre solo los proyectos de 'tamaño medio' y no las necesidades de aquellos a gran escala.
Para admitir proyectos de tamaño medio, nos centramos en el caso de uso de un tsconfig.json que hace referencia a otro.
Ejemplo tsconfig.json de hoy:
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"sourceMap": true
},
"files": [
"core.ts",
"sys.ts"
]
}
Sección tsconfig.json 'dependencias' propuesta:
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"sourceMap": true
},
"dependencies": [
"../common",
"../util"
],
"files": [
"core.ts",
"sys.ts"
]
}
Las dependencias apuntan a:
Las dependencias son jerárquicas. Para editar el proyecto completo, debe abrir el directorio correcto que contiene la raíz tsconfig.json. Esto implica que las dependencias no pueden ser cíclicas. Si bien puede ser posible manejar dependencias cíclicas en algunos casos, en otros casos, es decir, aquellos con tipos que tienen dependencias circulares, puede que no sea posible hacer una resolución completa.
Las dependencias se crean primero, en el orden en que se enumeran en la sección 'dependencias'. Si una dependencia no se genera, el compilador se cerrará con un error y no continuará con la compilación del resto del proyecto.
A medida que se completa cada dependencia, se pone a disposición de la compilación actual un archivo '.d.ts' que representa las salidas. Una vez que se completan todas las dependencias, se crea el proyecto actual.
Si el usuario especifica un subdirectorio como una dependencia, y también implica su compilación al no proporcionar una sección de 'archivos', la dependencia se compila durante la compilación de la dependencia y también se elimina de la compilación del proyecto actual.
El servicio de idiomas puede ver cada dependencia. Debido a que cada dependencia se eliminará de su propio tsconfig.json, esto puede significar que se necesitarían crear varias instancias de servicios de idiomas. El resultado final sería un servicio de lenguaje coordinado que fuera capaz de refactorizar, navegar por el código, encontrar todas las referencias, etc. a través de dependencias.
Agregar un directorio como dependencia que no tiene tsconfig.json se considera un error.
Se supone que los resultados de las dependencias son independientes y están separados del proyecto actual. Esto implica que no puede concatenar el .js de salida de una dependencia con el proyecto actual a través de tsconfig.json. Las herramientas externas, por supuesto, pueden proporcionar esta funcionalidad.
Como se mencionó anteriormente, las dependencias circulares se consideran un error. En el caso simple:
A - B
\ C
A es el 'proyecto actual' y depende de dos dependencias: B y C. Si B y C no tienen dependencias, este caso es trivial. Si C depende de B, B se pone a disposición de C. Esto no se considera circular. Sin embargo, si B depende de A, esto se considera circular y sería un error.
Si, en el ejemplo, B depende de C y C es autónomo, esto no se consideraría un ciclo. En este caso, el orden de compilación sería C, B, A, que sigue la lógica que tenemos para /// ref.
Si una dependencia no se va a reconstruir, se omite su paso de compilación y se reutiliza la representación '.d.ts' de la compilación anterior. Esto podría extenderse para manejar si la compilación de dependencias ha construido dependencias que aparecerán más adelante en la lista de 'dependencias' del proyecto actual (como sucedió en el ejemplo dado en la sección Limitaciones).
En lugar de tratar los directorios pasados como dependencias que no tienen un tsconfig.json como casos de error, podríamos aplicar opcionalmente 'archivos' predeterminados y la configuración del proyecto actual a esa dependencia.
¡Oh Dios mío!
: +1:
¡Sí! Esto tiene mucho sentido para los casos de uso que ha proporcionado. Proporcionar a las herramientas que usamos una mejor visión de cómo se pretende consumir nuestro código es definitivamente lo correcto. ¡Cada vez que F12 en un archivo .d.ts por error siento ganas de estrangular a un gatito!
Jonathan,
Muchas gracias por los amables comentarios y por decidir aceptar esto. TypeScript es una herramienta tan excelente y esta funcionalidad ayudará a muchas personas que desean componenteizar sus bases de código de tamaño mediano que no pueden justificar la ineficiencia exigida por proyectos enormes que se basan en una división estricta de preocupaciones (por ejemplo, los portales de Azure o el proyecto Monacos de el mundo con> 100kloc y muchos equipos independientes). En otras palabras, esto realmente ayudará a las "personas normales". Además, otros ya han propuesto cosas para esto, por ejemplo @NoelAbrahams (# 2180), y otros, así que no puedo reclamar originalidad aquí. Esto es solo algo que he estado necesitando por un tiempo.
Creo que tu propuesta es excelente. El único defecto que veo frente a mi propuesta (# 3394), que ahora he cerrado, es la falta de un mecanismo de respaldo para las referencias.
Considere el siguiente escenario del mundo real que detallé aquí: https://github.com/Microsoft/TypeScript/issues/3394#issuecomment -109359701
Tengo un proyecto de TypeScript grunt-ts que depende de un proyecto diferente csproj2ts. Casi nadie que trabaje en grunt-ts también querrá trabajar en csproj2ts, ya que tiene un alcance de funcionalidad muy limitado. Sin embargo, para alguien como yo, sería genial poder trabajar en ambos proyectos simultáneamente y refactorizar / ir a la definición / encontrar todas las referencias en ellos.
Cuando hice mi propuesta, sugerí que el objeto de dependencias fuera un objeto literal con fallbacks con nombre. Una versión más acorde con tu propuesta sería:
"dependencies": {
"csproj2ts": ["../csproj2ts","node_modules/csproj2ts/csproj2ts.d.ts"],
"SomeRequiredLibrary": "../SomeRequiredLibraryWithNoFallback"
}
Para simplificarlo para que siga siendo una matriz, sugiero la siguiente implementación alternativa de una sección hipotética futura dependencies
del archivo grunt-ts tsconfig.json
:
"dependencies": [
["../csproj2ts","node_modules/csproj2ts/csproj2ts.d.ts"],
"../SomeRequiredLibraryWithNoFallback"
]
La regla de resolución para cada elemento de tipo arreglo en dependencies
sería: el _primer_ elemento que se encuentra en cada uno es el que se usa, y el resto se ignora. Los elementos de tipo cadena se manejan tal y como establece la propuesta de Jonathan.
Esta es una solución un poco más complicada de implementar, sin embargo, le da al desarrollador (y a los autores de la biblioteca) una flexibilidad mucho mayor. Para los desarrolladores que no necesitan desarrollar en csproj2ts (y por lo tanto no tienen un archivo ../csproj2ts/tsconfig.json
), la dependencia será solo un archivo de definición que se agrega al contexto de compilación. Para los desarrolladores que _tienen_ un archivo ../csproj2ts/tsconfig.json
, la propuesta funcionará exactamente como lo describió anteriormente.
En el ejemplo anterior, se requeriría que "../SomeRequiredLibraryWithNoFallback"
esté allí como en su propuesta existente, y su ausencia sería un error del compilador.
Muchas gracias por considerar esto.
Hay dos problemas aquí que tenemos que romper, hay construcción y hay soporte de servicio de idiomas.
Para Build, no creo que tsconfig sea el lugar adecuado para esto. esto es claramente un problema del sistema de construcción. Con esta propuesta, el compilador de mecanografiado debe estar en los negocios de:
Todos estos son claramente responsabilidad de los sistemas de construcción; estos son problemas difíciles y ya existen herramientas que lo hacen, por ejemplo, MSBuild, grunt, gulp, etc.
Una vez que tsconfig y tsc se conviertan en el controlador de compilación, querrá que use todas las CPU para construir subárboles no relacionados, o tener comandos de compilación previa y posterior para cada proyecto, y posiblemente también compile otros proyectos. de nuevo, creo que existen herramientas de construcción que son buenas en lo que hacen, y no es necesario que las recreemos.
Para el servicio de idiomas,
Creo que está bien que las herramientas conozcan varios archivos tsconfig y puedan inferir de eso y ayudarlo más, pero eso no debería afectar su compilación. consideraría algo como:
"files" : [
"file1.ts",
{
"path": "../projectB/out/projectB.d.ts",
"sourceProject": "../projectB/"
}
]
Donde tsc solo buscará en "ruta", pero las herramientas pueden buscar otra información y tratar de ser lo más útiles posible.
Reconozco la existencia del problema, pero no creo que agrupar la construcción y las herramientas sea la solución correcta. tsconfig.json debe seguir siendo una bolsa de configuración (es decir, una alternativa json a los archivos de respuesta) y no convertirse en un sistema de compilación. un tsconfig.json representa una única invocación de tsc. tsc debe permanecer como un compilador de proyecto único.
Los proyectos de MSBuild en VS son un ejemplo del uso de un sistema de compilación para crear características IDE y ahora las personas no están contentas con él porque es demasiado grande.
Gracias por tu respuesta, Mohamed. Déjame reafirmar para ver si entiendo:
tsc --project
en este tsconfig.json
sería lo mismo que ejecutar tsc file1.ts ../project/out/project.d.ts
. Sin embargo, abrir un proyecto de este tipo en VS u otro editor con el servicio de lenguaje TypeScript permitiría "ir a la definición" para llevar al desarrollador al _archivo actual de TypeScript_ donde se definió la función (en lugar de la definición en projectB.d.ts
)¿Tengo ese derecho?
Si es así, creo que esto es muy justo. En mi propuesta original (https://github.com/Microsoft/TypeScript/issues/3394), dije que mi idea estaba incompleta porque no incluía el paso de copiar los resultados emitidos desde donde saldrían en la biblioteca referenciada a donde la biblioteca de referencia los esperaría en tiempo de ejecución. Creo que estás diciendo "por qué ir a la mitad del camino de la construcción cuando lo que realmente se necesita es el soporte del servicio de idiomas".
Para cambiar un poco los datos en su ejemplo, ¿estaría dispuesto a apoyar algo como esto?
"files" : [
"file1.ts",
{
"path": "externalLibraries/projectB.d.ts",
"sourceProject": "../projectB/"
}
]
El supuesto es que el proyecto actual se enviaría con una definición para el proyectoB que se usaría de forma predeterminada, pero si la fuente real para el proyectoB está disponible, se usaría la fuente real en su lugar.
@nycdotnet lo
¡Suena genial!
Estoy de acuerdo con @mhegazy y, de hecho, creo que es importante que TypeScript deje de pensar en sí mismo como un 'compilador' y comience a pensar en sí mismo como un 'verificador de tipo' y un 'transpilador'. Ahora hay soporte de transpilación de un solo archivo. No veo ninguna razón para que se creen archivos JavaScript compilados, excepto en el tiempo de ejecución / agrupación. Tampoco veo por qué es necesario generar las definiciones de referencia externas durante la verificación de tipos cuando la fuente de escritura mecanografiada real está disponible.
La resolución de archivos y paquetes es responsabilidad del sistema de compilación que está utilizando (browserify, systemjs, webpack, etc.), por lo que para que las herramientas funcionen, el servicio de idiomas debe poder resolver archivos de la misma manera que cualquier sistema / plataforma de compilación que usted utilice. están usando. Esto significa implementar un LanguageServicesHost personalizado para cada sistema de compilación o proporcionar una herramienta para cada uno que genere las entradas de mapeo correctas en tsconfig.json. Cualquiera de estos es aceptable.
@nycdotnet Creo que su caso de uso para múltiples rutas de respaldo se manejaría mejor usando npm link ../csproj2ts
?
Estoy de acuerdo con @mhegazy en que debemos mantener la compilación separada del compilador / transpilador. Me gusta incluir la dependencia tsconfig -> tsconfig en la sección de archivos, asumiendo que si la sección no enumera ningún archivo * .ts, todavía los busca. P.ej
"archivos": [
{
"ruta": "bibliotecas externas / proyectoB.d.ts",
"sourceProject": "../projectB/"
}
]
Aún incluirá todos los archivos ts en el directorio y subdirectorio que contiene el archivo tsconfig.json.
@dbaeumer , entonces quieres tenerlo en una propiedad diferente, ¿correcto? actualmente, si los archivos están definidos, siempre se usa e ignoramos la parte include * .ts.
@mhegazy no es necesariamente una sección diferente aunque
Creo que esto es muy necesario. Sin embargo, no creo que podamos evitar la cuestión de la construcción. Eso no significa que debamos implementar un sistema de compilación junto con esta propuesta, pero deberíamos haber pensado en alguna buena guía que funcione en una configuración como la propuesta. No será trivial hacerlo bien (y necesitamos resolverlo para Visual Studio).
En la propuesta anterior (donde se hace referencia tanto a .d.ts como a la fuente), ¿detecta si el .d.ts está desactualizado (es decir, necesita ser reconstruido)? ¿Las operaciones como Refactorizar / Renombrar funcionan en todos los proyectos (es decir, actualiza el nombre en la fuente del proyecto al que se hace referencia, no solo su archivo .d.ts que se sobrescribirá en la próxima compilación)? ¿GoToDef me lleva al código original en el proyecto al que se hace referencia (no al medio de un archivo .d.ts gigante para todo el proyecto)? Estos parecerían implicar la necesidad de resolver, y en algunos casos analizar, la fuente de los proyectos referenciados, ¿en qué caso es tan útil el .d.ts?
La solución general, que tenemos hoy, tiene un .d.ts como resultado de la compilación de un proyecto y luego se hace referencia como entrada en el otro proyecto. Esto funciona bien para la construcción, por lo que no es necesario cambiarlo.
El problema es el escenario de edición. no desea revisar un archivo generado durante la edición. Mi solución propuesta es proporcionar una "pista" de dónde provienen los .d.ts generados. El servicio de idiomas no cargará los .d.ts y, en su lugar, cargará un "proyecto" desde la ruta de la pista. de esta manera, goto def lo llevará al archivo de implementación en lugar del .d.ts y, de manera similar, los errores funcionarían sin la necesidad de una compilación.
operaciones como renombrar, se "propagarán" de un proyecto a otro, de manera similar, encontrar referencias, servirá.
Hoy depende completamente del host (el IDE, lo que sea) encontrar el archivo tsconfig.json, aunque TS luego proporciona API para leerlo y analizarlo. ¿Cómo imagina que esto funcione si hubiera varios tsconfig.json ubicados de manera jerárquica? ¿El anfitrión seguirá siendo responsable de resolver el archivo inicial pero no los demás o será el anfitrión responsable de resolver todos los tsconfigs?
Parece que hay un compromiso entre conveniencia / convenciones y flexibilidad.
¿No comenzaría esto con la capacidad de construir archivos d.ts como se describe en # 2568 (o al menos tener importaciones relativas)?
@spion, no estoy seguro de ver la dependencia aquí. puede tener múltiples salidas de un proyecto, no tiene que ser un solo archivo de delectación. el sistema de construcción debe poder saber eso y conectarlos como entradas a proyectos dependientes.
@mhegazy Vaya, lo siento. Mirando el tema nuevamente, parece que está más relacionado con el servicio de idiomas. Leí lo siguiente
- Proyectos de tamaño mediano: aquellos con compilaciones estándar y componentes compartidos
y asumió automáticamente que está relacionado con un mejor soporte para npm / browserify (o webpack) build worfklows donde partes del proyecto son módulos externos.
AFAIK, ¿todavía no hay forma de generar archivos .d.ts para módulos externos? Si es así, la única forma en que un servicio de idiomas podría vincular proyectos que importan módulos externos sería tener algo como esto en tsconfig.json:
{
"provides": "external-module-name"
}
que informaría al LS cuando se haga referencia a los proyectos en otro tsconfig.json
AFAIK, ¿todavía no hay forma de generar archivos .d.ts para módulos externos?
No creo que esto sea cierto. llamar a tsc --m --d
generará un archivo de declaración que es un módulo externo en sí mismo. La lógica de resolución intentará encontrar un .ts y, si no, un .d.ts con el mismo nombre,
@spion TypeScript puede generar archivos d.ts para módulos externos como dijo @mhegazy , pero esto da como resultado una proporción 1: 1 de definiciones a archivos fuente que es diferente de cómo se consumen típicamente las definiciones de TypeScript de una biblioteca. Una forma de evitar esto es esta biblioteca TypeStrong: https://github.com/TypeStrong/dts-bundle
@mhegazy lo siento, quise decir "módulos externos ambientales", es decir, si escribo external-module-name
en TypeScript e importo una de sus clases desde otro módulo:
import {MyClass} from 'external-module-name'
no hay forma de hacer que tsc
genere el archivo .d.ts apropiado que declare 'external-module-name'
@nycdotnet Soy consciente de dts-bundle y dts-generator, pero aún así, si el servicio de idiomas debe conocer la fuente de mi otro proyecto, también debería saber qué nombre de módulo proporciona para poder rastrear las importaciones correctamente
¿Cuál es el estado de esta función? parece que esta es una opción importante para proyectos de tamaño medio. ¿Cómo se configura un proyecto que tiene código fuente en diferentes carpetas con una configuración específica "requirejs"?
@llgcode, por favor, eche un vistazo a https://github.com/Microsoft/TypeScript/issues/5039 , esto debería estar disponible en typescript@next
.
Realmente no entiendo qué es tan difícil de escribir un gulpfile con tareas que compilen los subproyectos tal como lo necesita para proyectos de tamaño mediano. Incluso hago esto en proyectos de pequeño tamaño. La única razón por la que uso tsconfig.json es para VS Code
Primero no uso gulp. En segundo lugar, este puede ser un gran proyecto en el que no desea volver a compilar todo el tiempo. Pero si tiene una buena solución con gulp, déjeme saber cómo hacerlo.
@llgcode Bueno, gulp es un corredor de tareas. Escribe un archivo gulpfile.js donde define tantas tareas como desee con gulp.task()
. Dentro de su tarea, puede tomar un flujo de archivos de entrada con gulp.src()
y luego .pipe()
a través de una canalización de transformaciones, como compilación, concatenación, minificación, mapas de origen, copia de activos ... haga todo lo que sea posible con los módulos Node y NPM.
Si debe compilar varios proyectos, simplemente defina una tarea que haga esto. Si desea utilizar varios tsconfig.json, gulp-typescript tiene soporte para eso, o simplemente puede leer los archivos json. También son posibles las construcciones incrementales. No sé cómo está estructurado su proyecto, si los tiene en diferentes repositorios y usa submódulos, o lo que sea. Pero gulp es 100% flexible.
Ok, gracias parece ser una gran herramienta. si tengo require con mapeo como require ("mylibs / lib") y mis archivos están, por ejemplo, en una carpeta project / src / lib.js, entonces la finalización no funcionará en atom y no sé cómo se resolverá mecanografiado o gulp el mapeo / configuración hecho con "mylibs" y una ruta local. así que creo que esta nueva opción de rutas en # 5039 es una buena solución para este problema.
@llgcode Bueno, con gulp puede obtener todos los archivos (incluidos los archivos .d.ts) con globs, consulte https://www.npmjs.com/package/gulp-typescript#resolving -files.
Creo que TypeScript está tratando de hacer mucho aquí, es un transpilador y no una herramienta de compilación. La gestión de "dependencias" como se menciona en la propuesta es realmente la tarea de los administradores de paquetes o los sistemas de control de versiones y conectarlos juntos es la tarea de las herramientas de construcción.
@felixfbecker No estoy de acuerdo. Cada compilador (con verificación de tipos) que conozco tiene una opción como esta. por ejemplo:
gcc -> incluir archivos
java -> classpath y sourcepath
ir -> GOPATH
python -> PYTHONPATH
el compilador / transpilador necesita saber qué archivos de origen deben transpilarse, qué archivos de origen son solo archivos include / lib.
Se necesita una herramienta de compilación como gulp para saber qué hacer cuando cambia un archivo.
De acuerdo con @llgcode . Además, además de exponerse como compilador, TypeScript también se expone como un servicio de lenguaje, que proporciona resaltado de sintaxis (detección en realidad) y funcionalidad de finalización al IDE. Y ESO también necesita caminar por el árbol de dependencia.
@llgcode @unional Puntos válidos. Una cosa que también puede ayudar es hacer que la propiedad files
en tsconfig.json acepte globs para que pueda definir todos los archivos en todas las carpetas que desea incluir. Pero veo de dónde vienes y por qué uno puede querer múltiples tsconfig.json para proyectos más grandes.
AFAIK para CommonJS, esto ya es compatible a través de node_modules
y npm link ../path/to/other-project
El enlace npm no funciona tan pronto como comienzas a reutilizar las bibliotecas en los proyectos. Si usa una biblioteca común entre dos proyectos propios separados, (tomando rxjs como ejemplo) el mecanografiado le dirá que 'Observable no se puede asignar a Observable'. Esto se debe a que las rutas de inclusión siguen carpetas de enlaces simbólicos a dos carpetas node_modules diferentes y, a pesar de ser la misma biblioteca. Las soluciones alternativas dan como resultado la creación de tareas gulp o repositorios npm locales / privados, básicamente de vuelta a la opción de proyecto grande.
@EricABC probablemente se deba a que están usando declaraciones de módulos externos ambientales, en cuyo caso también deberían incluir definiciones para los archivos .d.ts basados en node_modules
recién admitidos. Aparte de eso, no debería haber ningún problema, ya que los tipos de TS solo se verifican estructuralmente, por lo que no importa si provienen de módulos diferentes o tienen nombres diferentes siempre que las estructuras coincidan.
Gracias @spion , asumí que estaba basado en archivos, parece que me vas a salvar de un dolor que me aflige a mí mismo.
Una cosa que también puede ayudar es hacer que la propiedad files en tsconfig.json acepte globs ...
Hay una propiedad include
en discusión
Preguntas y comentarios:
dependencies
debería permitir la ruta completa tsconfig.json porque tsc lo permitedependencies
) cuando files
ya existe y está bien?{
"compilerOptions": {
// ...
},
"files": [
"../common/tsconfig.json", // <== takes the `files` part of the tsconfig.json
"../common/tsconfig.util.json", // <==
"core.ts",
"sys.ts"
]
}
compilerOptions
?Vayamos más lejos / wild :-) y posiblemente permitamos (en el futuro) compilerOptions
, exclude
... para hacer referencia a otro tsconfig.json:
// File app/tsconfig.json
{
"compilerOptions": "../common/tsconfig.compilerOptions.json",
"files": [
"../common/tsconfig.json",
"../common/tsconfig.util.json",
"core.ts",
"sys.ts"
],
"exclude": "../common/exclude.json"
}
// File ../common/tsconfig.compilerOptions.json
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"sourceMap": true
}
}
// File ../common/exclude.json
{
"exclude": [
"node_modules",
"wwwroot"
]
}
// File ../common/tsconfig.util.json
{
"files": [
"foo.ts",
"bar.ts"
]
}
Tienes la lógica: files
, compilerOptions
, exclude
... puede hacer referencia a otros archivos tsconfig.json y solo "tomará" la parte de palabra clave coincidente del otro tsconfig .json file => fácil y escalable. Por lo tanto, puede dividir un tsconfig.json en varios archivos si lo desea y reutilizarlos.
Al leer parte de su discusión, parece más relevante hacer bien este "servicio de lenguaje" / goto definición. Los depuradores de JavaScript utilizan sourceMaps. Ahora, si tsc generó datos de sourceMap no solo en .js sino también en archivos .d.ts ...
Más allá de eso, realmente no veo mucho beneficio en activar compilaciones de proyectos secundarios desde el archivo tsconfig.json. Si necesita este tipo básico de dependencias de tiempo de compilación, un simple script de shell haría el trabajo. Si necesita un edificio incremental inteligente, por otro lado, el enfoque propuesto parece demasiado simple. En muchos escenarios, tsc termina siendo solo un paso de construcción entre otros. ¿Qué tan extraño escribir dependencias para tsc en tsconfig.json pero algún otro archivo para el resto? Nuevamente, para cosas simples con tsc como el único paso de compilación que haría un script de shell.
De todos modos, ¿qué tal generar mapeo de origen en archivos .d.ts como en archivos .js?
simplemente usamos módulos de nodo + enlace npm, lo único que no funciona es que moduleResolution: node no es compatible con los módulos ES6, que permiten optimizaciones de alineación / agitación de árboles (ver también # 11103)
No quiero salirse del tema, pero de alguna manera, esto parece paralelo a los desafíos de trabajar con múltiples proyectos de paquetes de Node a nivel local. No creo que sea tan simple como usar "enlace npm". Es posible que tengan diferentes scripts de compilación, necesitaría ejecutarlos todos en el orden correcto, es más difícil hacerlo de forma incremental, es más difícil usar el modo de observación, es más difícil depurar cosas y es más difícil resolver mapas de origen. Dependiendo de su editor de elección, esto podría ser aún más desafiante.
En general, me rindo, lo pongo todo en un proyecto gigante y luego lo divido en paquetes separados una vez que se han estabilizado, pero eso solo ayuda porque el desafío se enfrenta con menos frecuencia. Encuentro toda la experiencia realmente, realmente molesta. ¿Me estoy perdiendo de algo?
Entonces, sea lo que sea que esto termine siendo, solo espero poder finalmente tener una solución elegante para toda esta experiencia de desarrollo.
¡Solo estoy diciendo que esto sería genial para nuestro trabajo diario!
Debido a la naturaleza del desarrollo web, tenemos varios proyectos ts y cada proyecto contiene varios archivos ts compilados en un solo archivo js ( --outFile
). Estos son proyectos similares a aplicaciones (hacen algo específico o agregan una función específica) o proyectos similares a lib (código reutilizable para las aplicaciones). A menudo trabajamos en varios de estos proyectos ts al mismo tiempo, mejorando las bibliotecas para facilitar el desarrollo de las aplicaciones. Pero tampoco creo que ninguno de mis compañeros desarrolladores tenga todos nuestros proyectos ts en sus entornos locales en ningún momento.
Para mejorar nuestro flujo de trabajo, nuestras opciones actuales son
tsc -d -w
desde múltiples terminales, o iniciamos un script que lo hace para todos los subdirectorios donde se encuentra un tsconfig.Nuestro proyecto (s) simplemente no es lo suficientemente grande como para mantener el desarrollo de las bibliotecas estrictamente separado de las aplicaciones, pero no lo suficientemente pequeño como para que podamos unir todo. Nos encontramos sin opciones elegantes con mecanografiado.
Si dependencies
puede ser la mejor opción de ambos mundos, sería asombroso; la funcionalidad deetiquetas a todos los archivos ts de una dependencia, pero compile la salida de acuerdo con el propio tsconfig de esa dependencia.
¿Hay alguna actualización sobre este tema? ¿Cómo podemos tener varios proyectos mecanografiados que se compilan de forma independiente entre sí? ¿Cómo podemos describir tal dependencia en tsconfig.json?
Esto ahora se incluye en la hoja de ruta en la sección futura con el título "Soporte para referencias de proyectos". Entonces, supongo que un archivo .tsconfig
podrá vincular otro archivo .tsconfig
como dependencia.
¿Hay alguna actualización sobre este tema? ¿Cómo podemos tener varios proyectos mecanografiados que se compilan de forma independiente entre sí? ¿Cómo podemos describir tal dependencia en tsconfig.json?
La dependencia de compilación debe estar codificada en su sistema de compilación. Los sistemas de compilación como gulp, gruñido, brócoli, msbuild, basal, etc. están diseñados para manejar estos casos.
Para la información de tipo, la salida de un proyecto debe incluir un .d.ts y eso debe pasarse como entrada al otro.
@mhegazy Nuestro proyecto funciona así. Tenemos varios paquetes en un monorepo de lerna, cada paquete tiene sus propias dependencias en package.json, y esas mismas dependencias en la propiedad "types"
en su tsconfig.json
. Cada proyecto se compila con --outFile
(es un proyecto más antiguo que aún no se ha movido a los módulos ES), y los puntos clave "typings"
package.json
del paquete .d.ts
archivo.
Usamos gulp para agrupar / mirar.
Funciona en su mayor parte, pero hay algunos problemas:
.d.ts
incluido. Idealmente, esto lo llevaría a la fuente en otro proyecto.lerna run build --sort
(efectivamente tsc
en cada directorio), que tiene una sobrecarga adicional porque generará un proceso de compilación de TypeScript para cada paquete, realizando una gran cantidad de trabajo repetido .Estoy siguiendo de cerca este tema ya que también estamos en la misma situación que otros describieron.
Múltiples "proyectos", cada uno con su archivo tsconfig.json.
Tenemos el proceso de compilación funcionando como lo señaló .d.ts
y que se usa como entrada para los proyectos dependientes.
El problema real es la compatibilidad con IDE: cuando se buscan referencias, solo se encuentran dentro del alcance de un solo tsconfig.json
. Peor aún, los efectos en cascada de un archivo modificado no se propagan entre proyectos porque los archivos dependientes fuera del alcance tsconfig.json
no se vuelven a compilar. Esto es muy malo para el mantenimiento de nuestros proyectos y, a veces, provoca errores de compilación que podrían haberse detectado en el IDE.
OH DIOS MÍO
Un escenario actualizado en el que me encantaría tener esto involucra componentes de React. Tenemos un repositorio de componentes que contiene módulos JSX (átomos, moléculas y organismos) que hacen que los componentes de la interfaz de usuario sean apropiados para todas las aplicaciones de nuestra empresa. Todos los desarrolladores front-end utilizan este repositorio de componentes mientras trabajan en sus aplicaciones individuales. Sería MUY AGRADABLE si pudiera tener una experiencia de servicio de lenguaje TypeScript que me permitiera editar la interfaz de usuario de mi aplicación específica y "Ir a la definición" en el repositorio común de componentes de la interfaz de usuario. Hoy tenemos que agrupar estos componentes individualmente y copiarlos. Este es el problema de "hacer su propio proyecto de plomería" que me encantaría ver solucionado (para el cual hay una historia muy bonita en el mundo .NET con proyectos bajo solución).
TypeScript se ha escalado a proyectos de cientos de miles de líneas, pero no admite de forma nativa este tipo de escala como comportamiento integrado. Los equipos han desarrollado soluciones alternativas de diversa eficacia y no existe una forma estandarizada de representar grandes proyectos. Si bien hemos mejorado enormemente el rendimiento del comprobador de tipos a lo largo del tiempo, todavía existen límites estrictos en términos de qué tan rápido puede llegar TS de manera razonable,
y restricciones como el espacio de direcciones de 32 bits que impiden que el servicio de idiomas se amplíe "infinitamente" en escenarios interactivos.
De manera intuitiva, cambiar una línea de JSX en un componente de front-end no debería requerir volver a escribir la verificación de todo el componente de lógica empresarial central de un proyecto de 500.000 LOC. El objetivo de las referencias de dividir su código en bloques más pequeños. Al permitir que las herramientas operen en partes más pequeñas de trabajo a la vez, podemos mejorar la capacidad de respuesta y ajustar el ciclo de desarrollo central.
Creemos que a nuestra arquitectura actual le quedan muy pocos "almuerzos gratis" en términos de drásticas mejoras en el rendimiento o el consumo de memoria. En cambio, esta partición es una compensación explícita que aumenta la velocidad a expensas de un trabajo inicial. Los desarrolladores tendrán que dedicar algún tiempo a razonar sobre el gráfico de dependencia de su sistema, y es posible que ciertas características interactivas (por ejemplo, cambios de nombre entre proyectos) no estén disponibles hasta que mejoremos las herramientas.
Identificaremos las restricciones clave impuestas por este sistema y estableceremos pautas para el tamaño del proyecto, la estructura del directorio y los patrones de construcción.
Hay tres escenarios principales a considerar.
Algunos proyectos utilizan ampliamente importaciones relativas . Estas importaciones se resuelven sin ambigüedades en otro archivo en el disco. Las rutas como ../../core/utils/otherMod
serían comunes de encontrar, aunque generalmente se prefieren estructuras de directorio más planas en estos repositorios.
Aquí hay un ejemplo del proyecto perseus de Khan Academy:
Adaptado de https://github.com/Khan/perseus/blob/master/src/components/graph.jsx
const Util = require("../util.js");
const GraphUtils = require("../util/graph-utils.js");
const {interactiveSizes} = require("../styles/constants.js");
const SvgImage = require("../components/svg-image.jsx");
Si bien la estructura del directorio implica una estructura de proyecto, no es necesariamente definitiva. En la muestra de Khan Academy anterior, se puede inferir que util
, styles
y components
probablemente serían su propio proyecto. Pero también es posible que estos directorios sean bastante pequeños y en realidad se agrupen en una unidad de compilación.
Un repositorio único consta de varios módulos que se importan a través de rutas import * as C from 'core/thing
) pueden ser comunes. Por lo general, pero no siempre, cada módulo raíz se publica en NPM.
Adaptado de https://github.com/angular/angular/blob/master/packages/forms/src/validators.ts
import {InjectionToken, ɵisObservable as isObservable, ɵisPromise as isPromise} from '@angular/core';
import {forkJoin} from 'rxjs/observable/forkJoin';
import {map} from 'rxjs/operator/map';
import {AbstractControl, FormControl} from './model';
La unidad de división no es necesariamente la parte inicial del nombre del módulo. rxjs
, por ejemplo, en realidad compila sus subpartes ( observable
, operator
) por separado, al igual que cualquier paquete con alcance (por ejemplo, @angular/core
).
TypeScript puede concatenar sus archivos de entrada en un solo archivo JavaScript de salida. Las directivas de referencia, o el orden de archivos en tsconfig.json, crean un orden de salida determinista para el archivo resultante. Esto rara vez se usa para nuevos proyectos, pero aún es frecuente entre las bases de código más antiguas (incluido el propio TypeScript).
https://github.com/Microsoft/TypeScript/blob/master/src/compiler/tsc.ts
/// <reference path="program.ts"/>
/// <reference path="watch.ts"/>
/// <reference path="commandLineParser.ts"/>
https://github.com/Microsoft/TypeScript/blob/master/src/harness/unittests/customTransforms.ts
/// <reference path="..\..\compiler\emitter.ts" />
/// <reference path="..\harness.ts" />
Algunas soluciones que usan esta configuración cargarán cada outFile
través de una etiqueta script
separada (o equivalente), pero otras (por ejemplo, el propio TypeScript) requieren la concatenación de los archivos anteriores porque están creando salidas monolíticas .
Algunas observaciones críticas de la interacción con proyectos reales:
skipLibCheck
, son casi "gratuitos" en términos de verificación de tipo y costo de memoriaPoniendo todo esto en conjunto, si fuera posible solo verificar un fragmento de 50.000 LOC de código de implementación a la vez, casi no habría interacciones "lentas" en un escenario interactivo, y casi nunca nos quedaríamos sin memoria.
Introducimos un nuevo concepto, una referencia de proyecto , que declara un nuevo tipo de dependencia entre dos unidades de compilación de TypeScript donde no se comprueba el código de implementación de la unidad dependiente; en su lugar, simplemente cargamos su salida .d.ts
desde una ubicación determinista.
Se agrega una nueva opción references
(TODO: Bikeshed!) A tsconfig.json
:
{
"extends": "../tsproject.json",
"compilerOptions": {
"outDir": "../bin",
"references": [
{ "path": "../otherProject" }
]
}
}
La matriz references
especifica un conjunto de otros proyectos para hacer referencia a este proyecto.
Cada references
objeto path
apunta a un archivo tsconfig.json
o una carpeta que contiene un archivo tsconfig.json
.
Se pueden agregar otras opciones a este objeto a medida que descubramos sus necesidades.
Las referencias de proyectos cambian el siguiente comportamiento:
.ts
en un subdirectorio del rootDir
de un proyecto, en su lugar se resuelve en un archivo .d.ts
en el outDir
ese proyecto Referenced project "../otherProject" is not built
lugar de un simple "archivo no encontrado".Para mejorar significativamente el rendimiento de la compilación, debemos asegurarnos de restringir el comportamiento de TypeScript cuando ve una referencia de proyecto.
Específicamente, las siguientes cosas deberían ser ciertas:
tsconfig.json
de un proyecto referenciado debe leerse del discoPara mantener estas promesas, debemos imponer algunas restricciones a los proyectos a los que hace referencia.
declaration
se establece automáticamente en true
. Es un error intentar anular esta configuración.rootDir
defecto es "."
(el directorio que contiene el archivo tsconfig.json
), en lugar de inferirse del conjunto de archivos de entradafiles
, debe proporcionar los nombres de todos los archivos de entradanode_modules/@types
) no necesitan especificarsereferences
(que puede estar vacía)."declaration": true
?Las referencias de proyectos mejoran la velocidad de compilación mediante el uso de archivos de declaración (.d.ts) en lugar de sus archivos de implementación (.ts).
Entonces, naturalmente, cualquier proyecto referenciado debe tener declaration
configuración
Esto está implícito en "project": true
rootDir
?rootDir
controla cómo se asignan los archivos de entrada a los nombres de los archivos de salida. El comportamiento predeterminado de TypeScript es calcular el directorio de ["src/a.ts", "src/b.ts"]
producirá los archivos de salida ["a.js", "b.js"]
,
pero el conjunto de archivos de entrada ["src/a.ts", "b.ts"]
producirá los archivos de salida ["src/a.js", "b.js"]
.
Calcular el conjunto de archivos de entrada requiere analizar cada archivo raíz y todas sus referencias de forma recursiva,
que es caro en un proyecto grande. Pero no podemos cambiar este comportamiento hoy sin romper los proyectos existentes de una mala manera, por lo que este cambio solo ocurre cuando se proporciona la matriz references
.
Naturalmente, los proyectos no pueden formar un gráfico con circularidad. (TODO: ¿Qué problemas realmente causa esto, además de crear pesadillas de orquestación?) Si esto ocurre, verá un mensaje de error que indica la ruta circular que se formó:
TS6187: Project references may not form a circular graph. Cycle detected:
C:/github/project-references-demo/core/tsconfig.json ->
C:/github/project-references-demo/zoo/tsconfig.json ->
C:/github/project-references-demo/animals/tsconfig.json ->
C:/github/project-references-demo/core/tsconfig.json
tsbuild
Esta propuesta es intencionalmente vaga sobre cómo se usaría en un sistema de construcción "real". Muy pocos proyectos escalan más allá del límite "rápido" de 50.000 LOC sin introducir algo más que tsc
para compilar el código .ts.
El escenario del usuario de "No puedes construir foo
porque bar
aún no está construido" es un tipo de tarea obvia de "Ve a buscar eso" de la que una computadora debería encargarse, en lugar de que una carga mental para los desarrolladores.
Esperamos que herramientas como gulp
, webpack
, etc. (o sus respectivos complementos de TS) comprendan las referencias del proyecto y manejen correctamente estas dependencias de compilación, incluida la verificación actualizada.
Para garantizar que esto sea posible , proporcionaremos una implementación de referencia para una herramienta de orquestación de compilación de TypeScript que demuestra los siguientes comportamientos:
Esta herramienta debe usar solo API públicas y estar bien documentada para ayudar a los autores de herramientas a comprender la forma correcta de implementar referencias de proyectos.
Secciones a completar para completar completamente esta propuesta
tsconfig.json
y luego agregue las referencias necesarias para corregir los errores de compilaciónbaseUrl
dtsEmitOnly
para las personas que están canalizando su JS a través de, por ejemplo, webpack / babel / rollup?references
+ noEmit
implica esto¡Fantástico!
Descubre el escenario de Lerna
- El punto de datos disponible (N = 1) dice que no lo necesitarían porque su compilación ya está estructurada de manera efectiva de esta manera
¿"Esto" se refiere a la propuesta o la implementación de construcción de referencia? Si bien podría usar lerna para hacer la compilación (mi equipo lo hace), es complicado y sería mucho más eficiente si TS (o una herramienta creada a partir de esta propuesta) se encarga de sí misma.
La sección TODO es TODO para toda la propuesta.
¡Bonito!
Cualquier proyecto al que se haga referencia debe tener una matriz de referencias (que puede estar vacía).
¿Es esto realmente necesario? ¿No sería suficiente si dicho paquete tuviera archivos .d.ts
?
(En ese caso, ¿puede que ni siquiera sea necesario que haya un tsconfig.json
también?)
Mi caso de uso: considere un proyecto (por ejemplo, de terceros) que no usa outDir
, por lo que .ts
, .js
y .d.ts
estarán al lado de entre sí, y TS intentará compilar el .ts
lugar de usar el .d.ts
.
La razón para no usar outDir
para mí es permitir más fácilmente las importaciones de estilo import "package/subthing"
, que de lo contrario tendrían que ser, por ejemplo, import "package/dist/subthing"
con outDir: "dist"
.
Y poder usar el paquete NPM o su repositorio fuente directamente (por ejemplo, con npm link
).
(Sería útil si package.json
permitiera especificar un directorio en main
, pero lamentablemente ...)
¿Necesitamos una configuración dtsEmitOnly para las personas que están canalizando su JS a través de, por ejemplo, webpack / babel / rollup?
¡Absolutamente! Esta es una gran pieza que falta en este momento. Actualmente, puede obtener un solo archivo d.ts cuando usa outFile
, pero cuando cambia a módulos y usa un paquete, lo pierde. Ser capaz de emitir un solo archivo d.ts para el punto de entrada de un módulo (con export as namespace MyLib
) sería increíble. Sé que las herramientas externas pueden hacer esto, pero realmente sería genial si se integrara en los servicios de lenguaje y emisor.
¿Es esto realmente necesario? ¿No sería suficiente si dicho paquete tuviera archivos .d.ts?
Necesitamos algo en el tsconfig de destino que nos diga dónde esperar que estén los archivos de salida. Una versión anterior de esta propuesta tenía "Debe especificar un rootDir
explícito" que era bastante engorroso (tenía que escribir "rootDir": "."
en cada tsconfig). Dado que queremos cambiar una variedad de comportamientos en este mundo, tenía más sentido decir que obtienes un comportamiento de "proyecto" si tienes una matriz de referencias y eso es lo que está codificado, en lugar de especificar un montón de banderas que tendrías que indicar explícitamente.
Esta propuesta se alinearía estrechamente con la forma en que ya hemos estructurado nuestros proyectos de TypeScript. Nos hemos subdividido en unidades más pequeñas, cada una de las cuales tiene un tsconfig.json y se construye de forma independiente a través de gulp. Los proyectos se referencian entre sí haciendo referencia a los archivos d.ts.
En un mundo ideal, el proyecto al que se hace referencia no necesitaría ser preconstruido. es decir. TypeScript realiza una "compilación" del proyecto al que se hace referencia y mantiene el equivalente "d.ts" en la memoria del servicio de lenguaje. esto permitiría que los cambios realizados en el proyecto "fuente" aparezcan en el proyecto "dependiente" sin necesidad de una reconstrucción.
Necesitamos algo en el tsconfig de destino que nos diga dónde esperar que estén los archivos de salida.
Eso solo es cierto cuando se usa outDir
, ¿no es así?
Como en: si tengo un tsconfig que:
outDir
(pero tiene declaration: true
, por supuesto), entonces no necesitamos rootDir
, ni references
outDir
, entonces necesitaría references
y / o rootDir
(y declaration: true
) para ser configuradoLa razón para preguntar es que podría habilitar el 'modo de proyecto' para cualquier paquete TS con solo hacer referencia a él, es decir, está bajo mi control.
En ese caso, también sería bueno si también funciona tan pronto como encuentre el archivo .d.ts que está buscando (es decir, no se quejará si no hay archivos .ts o archivos tsconfig). Porque eso permitirá otro caso de 'reemplazar' una versión de NPM (que solo puede tener archivos .d.ts) por su versión de origen cuando sea necesario.
Por ejemplo, considere los paquetes de NPM MyApp y SomeLib.
SomeLib podría tener tsconfig: declaration: true
.
Repositorio como:
package.json
tsconfig.json
index.ts
sub.ts
Compilado, esto se convierte en:
package.json
tsconfig.json
index.ts
index.d.ts
index.js
sub.ts
sub.d.ts
sub.js
Esta estructura permite, por ejemplo,
// somewhere in MyApp
import something from "SomeLib/sub";
En el paquete NPM publicado, actualmente siempre tengo que eliminar los archivos .ts; de lo contrario, TS volverá a compilar todas las fuentes si MyApp usa SomeLib:
Entonces, en NPM, esto se convierte en:
package.json
index.d.ts
index.js
sub.d.ts
sub.js
Ahora, si pongo references: ["SomeLib"]
en el tsconfig de MyApp, sería bueno si funciona 'tal cual' tanto para la versión NPM como para la versión fuente de SomeLib , es decir, que no se quejará, por ejemplo, falta tsconfig, siempre que encuentre sub.d.ts
en el lugar correcto.
Pregunta relacionada, pero diferente:
Ahora me doy cuenta de que SI el autor de SomeLib
pone references
en su tsconfig, esto permitiría publicar paquetes NPM CON los archivos .ts, en el futuro. Pero entonces, supongo que TS siempre los recompilaría cuando cualquier paquete dependiente no ponga explícitamente references: ["SomeLib"]
en su tsconfig.
¿O la intención también es que references
en MyLib automáticamente también introduzca un 'límite de proyecto' cuando solo import
esté (es decir, no references
')?
IIRC, una de las ideas iniciales era que si un módulo estaba, por ejemplo, ubicado a través de node_modules
, entonces se preferirían los archivos .d.ts
archivos .ts
, pero esto se volvió a cambiar más tarde , porque la heurística ("hasta node_modules
") era demasiado problemática en general. ¿Podría ser que tener un 'límite de proyecto' explícito resolvería esto (por ejemplo, un projectRoot: true
, en lugar de o además de tener references
)?
Para el caso de lerna, esperaba una solución más sencilla.
Toda mi preocupación es que una vez que agrega una referencia usando una ruta "../xx"
relativamente descendente a los archivos de configuración del proyecto individual, ya no se pueden usar como módulos independientes; tienen que estar en una estructura de espacio de trabajo específica.
Agregar el nuevo concepto de un "espacio de trabajo" tsconfig.json resuelve este problema. De esa manera, si, por ejemplo, "clona git" el paquete individual, instalar sus dependencias de la manera normal (por ejemplo, usando npm o yarn) debería permitirle trabajar en él por separado, ya que las dependencias compiladas traerían sus archivos de definición. Si clona todo el espacio de trabajo y ejecuta el comando para traer todos los paquetes, la configuración del espacio de trabajo le permitirá navegar a través de todas las fuentes.
Tenga en cuenta que un espacio tsconfig.json
trabajo package.json
https://yarnpkg.com/lang/en/docs/workspaces/
Hice una pequeña prueba de concepto aquí.
https://github.com/spion/typescript-workspace-plugin
Simplemente agregue el complemento a todos sus archivos tsconfig.json
de los repositorios individuales
{
"plugins": [{"name": "typescript-workspace-plugin"}]
}
Luego, en el nivel superior package.json junto con la entrada "espacios de trabajo" de yarn, agregue una entrada "fuentes del espacio de trabajo":
{
"workspaces": ["packages/*"],
"workspace-sources": {
"*": ["packages/*/src"]
}
}
El campo funciona exáctamente como el campo "rutas" en tsconfig.json pero solo afecta el servicio de lenguaje de los proyectos individuales, apuntándolos a las fuentes del paquete. Restaura la funcionalidad adecuada de "ir a la definición / tipo" y similares.
Eso solo es cierto cuando se usa outDir, ¿no es así?
Correcto. Teníamos la hipótesis de que casi todos los que tienen un proyecto grande están usando outDir
. Me interesaría escuchar sobre proyectos que no
Ahora, si pongo referencias: ["SomeLib"] en el tsconfig de MyApp, sería bueno si funciona 'tal cual' tanto para la versión NPM como para la versión fuente de SomeLib
Gran fan, me gusta mucho esta idea. Necesito pensar si es realmente necesario o no.
Una advertencia aquí es que creo que los autores de paquetes deben a) publicar los archivos .ts y tsconfig juntos en un lugar donde TS los encuentre, ob) no publicar
¿O es la intención también que las referencias en MyLib también introduzcan automáticamente un 'límite de proyecto' cuando se lo importe (es decir, no se haga referencia a él)?
Hablamos con references
nunca "ve" un archivo .ts
fuera de la carpeta del proyecto, esto incluye archivos debajo de los directorios exclude
d. Este cambio solo hace que el escenario de lerna funcione ("trabajo" significa que "las referencias de módulo siempre se resuelven en .d.ts") fuera de la caja, así como otros.
Necesito mirar más el modelo de "espacio de trabajo".
Eso solo es cierto cuando se usa outDir, ¿no es así?
Correcto. Teníamos la hipótesis de que casi todos los que tienen un gran proyecto utilizan outDir. Me interesaría escuchar sobre proyectos que no
Tenemos 67 proyectos TS en la solución de Visual Studio que se compilan sin outdir
y grunttasks postbuild para crear la estructura del directorio de salida (y uglify y otros postprocesos).
La mayoría de los proyectos tienen un tsconfig.json.
"include": [
"../baseProj/Lib/jquery.d.ts",
"../baseProj/baseProj.d.ts"
]
Me tomé un tiempo para leer la propuesta de referencias y corregir: los usuarios del espacio de trabajo de AFAICT lerna y yarn no necesitan ninguna de las funciones del espacio de trabajo propuestas aquí:
skipLibCheck
debería hacer que el impacto en el rendimiento sea insignificante, pero no lo he comprobado.Lo que no tenemos, y lo que proporciona el complemento que escribí, es una forma de cargar todas las fuentes al mismo tiempo. Cuando necesito hacer cambios en dos o más módulos al mismo tiempo, no quiero que "ir a la definición" y "ir a la definición del tipo" me envíen al archivo .d.ts. Quiero que me envíe a la ubicación del código fuente original, para que quizás pueda editarlo. De lo contrario, simplemente cargaría el directorio del proyecto individual y los enlaces simbólicos node_modules creados por lerna / yarn simplemente funcionarían.
Lo mismo para nosotros. En lugar de Lerna, usamos Rush para calcular nuestro gráfico de dependencia, pero el efecto es el mismo. Cuando construimos proyectos, tsc
es solo una de las muchas tareas que deben ejecutarse. Nuestras opciones del compilador se calculan mediante un sistema de compilación más grande, y nos estamos moviendo a un modelo donde tsconfig.json no es un archivo de entrada, sino una salida generada (principalmente para el beneficio de VS Code).
Lo que no tenemos, y lo que proporciona el complemento que escribí, es una forma de cargar todas las fuentes al mismo tiempo. Cuando necesito hacer cambios en dos o más módulos al mismo tiempo, no quiero que "ir a la definición" y "ir a la definición del tipo" me envíen al archivo .d.ts. Quiero que me envíe a la ubicación del código fuente original, para que quizás pueda editarlo.
+1 esto sería genial.
Si estamos soñando con un mejor soporte para múltiples proyectos, mi primera solicitud sería un servicio de compilación, algo así como cómo funciona VS Code IntelliSense. Nuestras compilaciones serían significativamente más rápidas si Rush pudiera invocar tsc
100 veces sin tener que hacer girar el motor del compilador 100 veces. El compilador es uno de nuestros pasos de compilación más costosos. En un monorepo, los tiempos de construcción son realmente importantes.
@iclanton @ nickpape-msft @ qz2017
¡Sí, por favor!
Creo que uno de los resultados más útiles del sistema de proyectos sería si
'ir a la definición' fue al archivo fuente en lugar del archivo d.ts y
"Buscar todas las referencias" buscado en el árbol de referencia del proyecto.
Es de suponer que esto también desbloquearía las refactorizaciones de tipo de 'cambio de nombre global'.
El jueves 9 de noviembre de 2017 a las 9:30 p.m. Salvatore Previti [email protected]
escribió:
¡Sí, por favor!
-
Estás recibiendo esto porque estás suscrito a este hilo.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/Microsoft/TypeScript/issues/3469#issuecomment-343356868 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AANX6d19Zz7TCd_GsP7Kzb-9XJAisG6Hks5s07VXgaJpZM4E-oPT
.
Hablamos con
Bien, y en ese caso, ¿por qué habría que especificar referencias específicas?
Parece que sería suficiente tener una bandera (como projectRoot: true
).
Por ejemplo, ¿cuál sería la diferencia entre references: ["foo"]
y solo references: []
?
Porque si import "foo"
o import "bar"
, ambos ignorarán los archivos .ts
.
Entonces, en ese caso, la propuesta se convierte en:
Dado este tsconfig.json (TODO bikeshed en projectRoot
):
{
"extends": "../tsproject.json",
"compilerOptions": {
"projectRoot": true
}
}
Cuando tsc
necesita resolver algo fuera de la carpeta del proyecto (incluidos los archivos de los directorios excluidos), solo verá los archivos .d.ts
(alternativamente, puede que simplemente _preferir_ .d.ts
archivos, y vuelva a tsconfig
y / o .ts
si solo ve eso).
Esto hace que la resolución durante la compilación sea rápida y sencilla.
Funciona para referencias de monorepo (es decir, import "../foo"
) y referencias basadas en paquetes (es decir, import "foo"
).
Funciona para paquetes NPM y su representación de código fuente.
Y elimina la necesidad de resolver la maquinaria tsconfig.json
durante la compilación, aunque el mensaje de error si no puede encontrar el .d.ts
será menos útil.
Suena demasiado bueno para ser verdad, si es que es así de simple, así que probablemente estoy pasando por alto algo importante :)
Como otros también señalan, sigue siendo muy importante que 'IntelliSense' siga funcionando con los archivos .ts.
Por lo tanto, si se hace una solicitud para 'ir a la definición', 'buscar referencias', etc., debe usar un mapeo inverso para ubicar el archivo .ts
archivo .d.ts
que usó entonces lejos.
Este mapeo se puede hacer usando, por ejemplo:
//# sourceURL = ../src/foo.ts
en .d.ts
.d.ts
'enrollado' hasta el .ts
.js
, y usando su mapa fuente para ubicar el archivo `.tsEsto introduce el tema de la reconstrucción de .d.ts
cuando se cambia ese .ts
, pero no estoy seguro de que deba resolverse con esta propuesta. Por ejemplo, hoy en día ya es el caso de que debe haber algún proceso para reconstruir los archivos .js
, incluso desde el proyecto raíz mismo. Así que supongo que sería seguro asumir que si eso está presente, también habrá algo para reconstruir las dependencias. Podría ser un montón de tsc
paralelos para cada paquete, podría ser tsbuild
, podría ser un IDE inteligente con compileOnSave
comportamiento similar a
@pgonzal @michaelaird https://github.com/spion/typescript-workspace-plugin solo hace eso: restaura ir a la definición y encontrar todas las referencias para un proyecto de espacio de trabajo multi-tsconfig yarn / lerna / etc.
Interesante ... Me pregunto si podríamos hacer que esto funcione con Rush. Echaremos un vistazo.
Para su información, otra herramienta simple que construimos como parte de este esfuerzo fue wsrun
Similar a lerna run
, ejecuta un comando para todos los paquetes en el espacio de trabajo.
Dado que las dependencias de mecanografiado deben compilarse en orden, wsrun es capaz de ejecutar un comando de paquete en un orden topológico basado en sus dependencias package.json
. Es compatible con el paralelismo durante la construcción. No es un paralelo óptimo, pero eso se puede mejorar más adelante.
Solo una nota, oao es otra herramienta monorepo para hilo. Recientemente también agregó soporte para el ordenamiento 'topológico' de comandos.
Solo me gustaría publicar la palabra "refactorización" aquí, ya que es un objetivo importante para nosotros, aunque probablemente tangencial a la propuesta actual (https://github.com/Microsoft/TypeScript/issues/3469#issuecomment-341317069) y no se menciona en este número muy a menudo.
Nuestro caso de uso es un monorepo con varios proyectos de TS, básicamente se puede reducir a common-library
más un par de aplicaciones: app1
y app2
. Cuando se trabaja en el IDE, estos deben tratarse como un solo proyecto, por ejemplo, la refactorización de cambio de nombre debería funcionar en los tres módulos, pero app1
y app2
también son dos objetivos de compilación separados. Si bien estoy de acuerdo en que la compilación es generalmente una preocupación separada, la verdad es que nuestras aplicaciones son bastante pequeñas y hacer algo como cd app1 && tsc
estaría perfectamente bien para nosotros.
Si TypeScript encuentra una buena manera de respaldar esto, sería increíble.
Para la refactorización / referencias de proyectos cruzados de monorepo, encontré que esta configuración me funciona si está trabajando en vscode:
tsconfig raíz:
"compilerOptions": {
"baseUrl": ".",
// global types are different per project
"types": [],
"paths": {
"lib": ["packages/lib/src"],
"xyz1": ["packages/xyz1/src"],
"xyz2": ["packages/xyz2/src"],
}
},
"include": ["./stub.ts"], // empty file with export {} to stop vscode complaining about no input files
"exclude": ["node_modules"]
paquetes / xyz1 / tsconfig.json
{
"extends": "../../tsconfig",
"compilerOptions": {
"types": ["node"],
},
"include": ["src/**/*"]
}
paquetes / xyz2 / tsconfig.json
{
"extends": "../../tsconfig",
"compilerOptions": {
"types": ["webpack-env"]
},
"include": ["src/**/*"]
}
paquetes / lib / tsconfig.json
{
"extends": "../../tsconfig",
"compilerOptions": { ... },
"include": ["src/**/*"],
// special file to load referenced projects when inside in lib package, without it they won't be
// visible until you open some file in these projects
"files": ["./references.ts"],
}
paquetes / lib / tsconfig-build.json
{
"extends": "./tsconfig",
// exclude referenced projects when building
"files": []
}
paquetes / lib / referencias.ts
import "xyz1";
import "xyz2";
export {};
Necesita la propiedad main
correcta en el paquete package.json
y puede ser types
incluso para paquetes sin lib, por ejemplo:
"main": "src/main.tsx",
"types": "src/main.tsx",
De esta manera, refactorizar / renombrar algo en lib
también refactorizará las referencias en xyz1
y xyz2
. También los proyectos podrían tener diferentes bibliotecas globales / de destino de esta manera.
En Gradle, simplemente lo llaman: construcción compuesta .
Por cierto, ¿me puede indicar si debo comenzar si quiero contribuir al compilador de TypeScript? Cloné el repositorio y no es poca cosa (uso para leer la fuente: angular, iónica, expresa cuando no puedo obtenerla de los documentos o estoy lejos de Internet ...) Realmente necesito ayuda de uno para indicarme el camino a seguir, por favor.
¡Gracias!
Futuro brillante para TypeScript.
Tengo un prototipo que me gustaría que la gente probara si están usando rutas de módulo relativas. Hay un repositorio de muestra en https://github.com/RyanCavanaugh/project-references-demo que describe el escenario básico y muestra cómo funciona.
Para probar localmente:
git clone https://github.com/RyanCavanaugh/TypeScript
git checkout pr-lkg
npm install
npm run build
npm link
Luego, en su otra carpeta:
npm link typescript
Mantendré la etiqueta pr-lkg
apuntando a la última confirmación de trabajo a medida que cambien las cosas. A continuación en mis todos:
@RyanCavanaugh Realmente no puedo construirlo debido a errores como faltar el módulo del
o Error: Cannot find module 'C:\github\TypeScript\built\local\tsc.js'
(¿tal vez su ruta local?) Pero en general, la estructura se ve muy bien.
¿Es esto tsc
-only o también tendrá en cuenta las refactorizaciones de todo el proyecto en VSCode con el servidor de idiomas?
... también falta la etiqueta pr-lkg
.
La etiqueta está ahí (no es una rama). Ver https://github.com/RyanCavanaugh/TypeScript/tree/pr-lkg
El references
en tsconfig.json
es opt-in por dependencia, ¿no tendría más sentido que se aplicara a todo lo que se resuelve fuera de rootDir
?
Me estoy imaginando algo así como una propiedad sandbox
que podría verse así:
# tsconfig.json
{
"compilerOptions": {
"outDir": "lib",
"sandbox": "."
},
"include": ["src/index.ts"]
}
Sandbox también establecería rootDir
en el mismo valor. En lugar de proporcionar explícitamente rutas a directorios que contienen tsconfig.json
, se aplicaría la resolución normal del módulo, y podría buscar en el árbol FS para encontrar tsconfig.json
automáticamente.
# package.json
{
"name": "animals",
"module": "src",
"typings": "lib",
"dependencies": {
"core": "*"
}
}
De esta manera:
references
y dependencies
).@RyanCavanaugh , hasta donde tengo entendido, solo puedo trabajar localmente con estos cambios y no podré enviar tales proyectos para pruebas, por ejemplo, en travis-ci.org. ¿Derecha?
Notas de una reunión de hoy con @billti / @mhegazy
Barra lateral: este cambio de nombre no funciona hoy
function f() {
if (Math.random() > 0.5) {
return { foo: 10 };
} else {
return { foo: 20 };
}
// rename foo here doesn't rename *both* instances in the function body
f().foo;
Gracias Ryan, Mohamed y Bill. Hacer que el escenario Buscar referencias / Renombrar funcione en todos los proyectos fue uno de los casos de uso principales que tenía en mente cuando presenté la queja original acerca de que TypeScript no admite proyectos de tamaño mediano. Los proyectos de tamaño mediano son modulares pero no grandes. La propuesta y el trabajo que he visto aquí hasta ahora se sienten más como un juego de escalabilidad. Esto es muy importante para la salud a largo plazo de TypeScript, pero es más beneficioso para proyectos grandes, no medianos. Las cosas que escucho en este comentario de Ryan suenan más en la línea de lo que se necesita para mejorar la ergonomía del desarrollo de proyectos de tamaño mediano en TypeScript.
Como siempre, ¡muchas gracias a todo el equipo de TypeScript por sus esfuerzos! Estás haciendo un trabajo increíble.
Hay un truco con el espacio de trabajo de lerna / yarn que te hará la vida mucho más fácil.
Apunta las entradas main
y types
en tu package.json de los subproyectos a tu src / index. ts , y el escenario Buscar referencias / Cambiar nombre simplemente funcionará.
Y podrá compilar todo su proyecto con un solo tsc en ejecución.
Puede hacer eso para algunos de sus paquetes, puede hacerlo para todos. tu llamada.
Hay algunos inconvenientes y trampas (si tiene aumento en un paquete o la importación de cualquier símbolo global, contaminará todo su programa), pero en general funciona muy bien.
Cuando desee publicar en NPM, simplemente configure los tipos principales y los valores apropiados (como parte de su compilación, más o menos)
Con la configuración anterior, obtuve más o menos todas las características esperadas
aquí hay un truco con el espacio de trabajo de lerna / yarn que te hará la vida mucho más fácil.
Apunte las entradas principales y de tipos en su package.json de los subproyectos a su archivo src / index.ts, y el escenario Buscar referencias / Renombrar simplemente funcionará.
En mi experiencia, el problema con esa configuración es que TypeScript comenzará a tratar los archivos ts de los paquetes _external_ como si fueran _sources_ del paquete que los requiere, no como bibliotecas externas. Esto provoca una serie de problemas.
Los paquetes externos se compilan varias veces, cada vez utilizando el tsconfig del paquete _requiring_. Si los paquetes requeridos tienen tsconfigs diferentes (por ejemplo, diferentes bibliotecas), esto puede causar que aparezcan errores de compilación falsos en el paquete requerido hasta que se compile de nuevo.
Los paquetes que requieren también se compilan más lentamente porque incluyen más archivos de los necesarios.
El rootDir
de todos los paquetes se convierte en el directorio de nivel superior, lo que potencialmente permite la inclusión directa de cualquier archivo TS de cualquier paquete, en lugar de solo incluirlo desde index
. Si los desarrolladores no tienen cuidado, pueden omitir la API del paquete requerido. Además, si el proceso de compilación no es sólido, los paquetes requeridos pueden terminar conteniendo código duplicado del paquete requerido que estaba destinado a ser externo.
En nuestros proyectos hemos descartado la dependencia de archivos TS por los inconvenientes. Todas las dependencias entre paquetes están en los archivos index.d.ts , por lo que el compilador las trata como externas y todo está bien.
Por supuesto, dependiendo de .d.ts
tiene el problema de requerir una compilación de varios pasos (no es posible de inmediato con herramientas como el paquete web) y el problema de una mala experiencia con IDE (cambios de nombre, referencias que no cruzan los límites del paquete ).
Estoy de acuerdo con algunos de los otros sentimientos: el mecanografiado es un compilador, no un sistema de compilación. Necesitamos nuestras herramientas para respaldar mejores compilaciones de proyectos múltiples. Sé que hay algunas opciones en la comunidad que comienzan a hacer esto. Como ejemplo, C # tiene un compilador llamado Roslyn y una herramienta de compilación llamada MSBuild.
Debate hoy con @mhegazy sobre cómo hacer que el cambio de nombre funcione con la menor molestia posible.
El peor caso no degenerado para el cambio de nombre se ve así:
// alpha.ts
const v = { a: 1 };
export function f() { return v; }
export function g() { return v; }
// alpha.d.ts (generated)
export function f(): { a: number };
export function g(): { a: number };
// beta.ts (in another project)
import { f } from '../etc/alpha';
f().a;
// gamma.ts (in yet another project)
import { g } from '../etc/alpha';
g().a;
La observación clave es que es imposible saber que cambiar el nombre de f().a
debería cambiar el nombre de g().a
menos que pueda ver alpha.ts
para correlacionar los dos.
Un bosquejo del plan de implementación:
@RyanCavanaugh irá a la definición / ¿buscará que todas las referencias funcionen con este modelo?
Notas de una discusión anterior con Anders y Mohamed sobre una gran cantidad de preguntas abiertas
prepend
también se aplica a .d.ts
? sí@internal
en la rama de prueba interna? Necesitamos mantener las declaraciones internas en los archivos .d.ts locales, pero no queremos que aparezcan en las versiones de salida.--stripInternal
remove-internal
(doneish)@internal
@types
?noEmitOnError
obligatorio? Si.referenceTarget
-> composable
✨ 🚲 🏡 ✨tsbuild
o su equivalente puede verificar su cumplimiento con los requisitos no relevantes de upstream de composable
{ path: "../blah", circular: true }
si desea hacer estoMiscelánea
Ya he perdido. En su mayoría, solo quería mantener la interpretación de los mapas de origen fuera del compilador (responsabilidades separadas para herramientas separadas) pero mientras no estaba, trabajé en agregarlo de todos modos (porque aparentemente es deseable una definición perfecta).
@RyanCavanaugh
¿Debería renombrar / encontrar todas las referencias que funcionen en los proyectos referenciados después de fusionar # 23944? ¿También deberíamos usar composite: true
y projectReferences: []
en caso de que solo se necesiten servicios de idiomas (pero no tsbuild)?
¿Debería renombrar / encontrar todas las referencias que funcionen en los proyectos referenciados después de fusionar # 23944?
todavía no. pero estamos trabajando en esto a continuación.
También deberíamos usar composite: true y projectReferences: [] en caso de que solo se necesiten servicios de lenguaje (pero no tsbuild)?
No estoy seguro de entender la pregunta. ¿Qué quiere decir "servicio de idiomas" y no "construir"?
No estoy seguro de entender la pregunta. ¿Qué quiere decir "servicio de idiomas" y no "construir"?
Solo me interesa la compatibilidad con el editor (cambiar el nombre / buscar todas las referencias / etc ...) en múltiples proyectos en monorepo, no en la nueva herramienta de compilación (también conocida como build mode
) (# 22997) ya que estoy usando babel para mi compilación.
Eso debería funcionar. build es una función opcional, no es necesario que la use si no desea ... similar a cómo tsc
no es necesario para su experiencia de servicio de idiomas en VSCode, por ejemplo.
Sin embargo, es probable que deba compilar con declaraciones y mapas de declaraciones para producir los metadatos necesarios para que funcionen las referencias de proyectos cruzados.
No estoy seguro de haber entendido correctamente todos los aspectos de la propuesta, pero ¿sería posible que los proyectos individuales no hicieran referencia a otros por ruta, sino por su nombre? El proyecto del espacio de trabajo debe tener una forma de especificar cada ruta de proyecto, similar a los espacios de trabajo de hilo a través de globs, o tal vez enumerando cada nombre de proyecto individual:
Básicamente, en lugar de:
"dependencies": [
"../common",
"../util"
],
¿Podemos por favor tener
"dependencies": [
"common",
"util"
],
y tener un espacio de trabajo tsconfig.json
"workspace": {
"common": "packages/common",
"util": "packages/util"
}
O mejor aún, sintaxis de rutas:
"workspace": {
"*":"packages/*"
}
Beneficios:
O al menos, ¿podemos tener los nombres que no son de ruta (aquellos que no comienzan con './' o '../') reservados para uso futuro ...
No estoy seguro de cuánto está relacionado esto, pero Yarn 1.7 introdujo recientemente un concepto de "espacios de trabajo enfocados", vea esta publicación de blog .
¿Alguien aquí está lo suficientemente familiarizado con los espacios de trabajo y el trabajo que @RyanCavanaugh está haciendo en torno a las referencias del proyecto / modo de compilación de TypeScript para tal vez dejar un comentario explicando si se relacionan en absoluto? Mi intuición es que _en algún lugar_ entre los espacios de trabajo de Yarn (npm también los obtendrá este año) y las futuras versiones de TypeScript se encuentra un buen soporte para monorepos con múltiples proyectos y bibliotecas compartidas. (Sentimos el dolor, actualmente).
Realmente me encantaría recibir una actualización sobre el progreso de esta función. Estamos planeando trasladar Aurelia vNext a un monorepo en el próximo mes más o menos. Nuestra nueva versión es 100% TypeScript y nos encantaría usar un sistema de proyecto TS oficial en lugar de Lerna, si podemos. También estamos felices de ser los primeros en adoptar / probar las nuevas funciones :)
El soporte básico y la definición de goto usando el soporte del tsc --b
para soporte de compilación ya está disponible y está destinado a TS 3.0. La base del código mecanografiado se ha movido para usarlo. Actualmente estamos probando este soporte usando el repositorio de mecanografiado.
Lo que aún se necesita en este punto por hacer: 1. obtener buscar todas las referencias / cambiar el nombre para trabajar en escenarios de múltiples proyectos. 2. abordar la actualización de archivos .d.ts en segundo plano en el editor, y 3. --watch
soporte para escenarios de múltiples proyectos. también muchas, muchas pruebas.
Este boleto ha estado en los libros durante 3 años. ¿Aún quedan 3/6 artículos pendientes?
@claudeduguay Este es un cambio fundamental en los proyectos que admite TypeScript, es hora de celebrar, ¿no crees? ¡Estoy muy feliz por esto!
@mhegazy Esta es una gran noticia. Estoy muy feliz de saber que el equipo de TS también lo está probando en su propio proyecto. Esperando que se terminen las últimas cosas y tener esto como una opción para Aurelia :) Tan pronto como haya algo de documentación sobre cómo configurarlo, trasladaremos nuestro vNext al nuevo sistema de proyectos. ¡No puedo esperar!
@mhegazy ¿Puede arrojar algo de luz sobre cómo funcionaría todo esto con los archivos y proyectos package.json basados en módulos ES2015? Por ejemplo, en Aurelia vNext, tenemos paquetes como @aurelia/kernel
, @aurelia/runtime
, @aurelia/jit
, etc. Esos son los nombres de los módulos que se usarán en import
declaraciones a lo largo de los distintos proyectos. ¿Cómo entenderá el compilador de TS que los nombres de estos módulos se asignan a las diversas carpetas a las que se hace referencia? ¿Recogerá los archivos package.json ubicados en cada carpeta a la que se hace referencia? ¿En qué se diferenciará de Lerna o Yarn Workspaces? Mi mirada inicial a los enlaces anteriores me hace pensar que necesitaría usar proyectos de TS (compilación) en combinación con Lerna (enlace de depuración y publicación) para obtener una solución que funcione, pero no veo cómo TS se va a construir correctamente. si no se puede integrar con package.json y node_modules. La fuente del repositorio de TS es bastante diferente a su proyecto Lerna promedio (nada parecido en realidad), así que estoy empezando a preguntarme si esto podrá satisfacer nuestras necesidades. Cualquier otra información que pueda proporcionar, y esp. una configuración de solución de demostración funcional similar a la que he descrito aquí, sería muy útil. ¡Gracias!
Comparto las mismas preguntas que @EisenbergEffect. En particular, también espero que esto funcione bien con un monorepo administrado por lerna
.
Dos escenarios de monorepo a considerar
Comencemos con una configuración en la que haya enlazado todo con lerna:
/packages
/a
/node_modules
/b -> symlink to b with package.json "types" pointing to dist/index.d.ts
/b
/dist
/index.d.ts -> built output of entry point declaration file
Lo clave que queremos que suceda aquí es reconstruir b
que construimos a
iff a
está desactualizado. Así que agregaríamos "references": [ { "path": "../b" } ]
a a
's tsconfig.json
y ejecutaríamos tsc --build
en a
para obtener compilaciones ascendentes correctas de b
. En este mundo, las referencias de proyectos simplemente sirven como una representación del gráfico de construcción y permiten reconstrucciones de incrementos más inteligentes. Idealmente, lerna y TS podrían cooperar aquí y reflejar las dependencias package.json
en tsconfig.json
cuando corresponda.
Otro escenario (probablemente menos común) sería si no estuvieras enlazando simbólicamente pero aun así quisieras "actuar como si" estuvieras trabajando en un conjunto de paquetes en vivo. Puede hacer esto hoy con un mapeo de rutas bastante tedioso, y algunas personas lo hacen. Las referencias de proyectos aquí ayudarían de manera similar con el orden de compilación, pero sería muy deseable tener soporte para una propiedad en el archivo tsconfig de referencia para crear automáticamente un mapeo de ruta siempre que se haga referencia a él; por ejemplo, si tuvieras
{
"compilerOptions": { "outDir": "bin" },
"package": "@RyanCavanaugh/coolstuff"
}
luego agregar "references": [{ "path": "../cool" }]
automáticamente agregaría un mapeo de ruta de @RyanCavanaugh/coolstuff
-> ../cool/bin/
. No hemos agregado esto todavía, pero podemos analizarlo si resulta ser un escenario más común.
Idealmente, lerna y TS podrían cooperar aquí y reflejar las dependencias package.json en tsconfig.json donde sea apropiado
En lugar de depender de herramientas externas, podríamos optar por leer su package.json
(siempre que esté junto con su tsconfig) como referencias potenciales si composite: true
está configurado (verifique si cada paquete resuelto tiene un tsconfig.json
, si tiene uno, considérelo un nodo de proyecto construible y repita). Dado que todo está enlazado simbólicamente en su lugar, ni siquiera deberíamos necesitar alterar la resolución (¿mucho? ¿Alguna?) Para manejar el espacio de trabajo. Lerna en realidad no configura ningún elemento específico de ts (o específico de compilación) como es afaik, simplemente enlaza todo en su lugar y administra el control de versiones. Esto sería una optimización de lo que hacemos hoy, que es cargar los archivos ts
(ya que los preferimos a las declaraciones) y volver a compilar todo sin importar si están desactualizados.
@RyanCavanaugh Esto suena muy emocionante. ¿Alguna idea de si funcionará con la estrategia de enlace simbólico common / temp / package.json que contiene el superconjunto de todas las dependencias para todos los paquetes en el repositorio. Luego usamos pnpm para realizar una sola operación de instalación para este paquete sintético. (PNPM utiliza enlaces simbólicos para crear un gráfico acíclico dirigido en lugar de la estructura de árbol de NPM, lo que elimina las instancias de biblioteca duplicadas). Luego, Rush crea una carpeta node_modules para cada proyecto en el repositorio, hecha de enlaces simbólicos que apuntan a las carpetas apropiadas en common / temp . El resultado es totalmente compatible con TypeScript y el algoritmo de resolución estándar de NodeJS. Es muy rápido porque hay un archivo shrinkwrap y una ecuación de control de versiones para todo el repositorio, al tiempo que permite que cada paquete especifique sus propias dependencias.
No ponemos nada especial en tsconfig.json
para este modelo. Si se requiere alguna configuración especial de TypeScript para la función de ir a definición, lo ideal sería que la autogenerara durante la instalación en lugar de tenerla almacenada en Git.
@pgonzal ¡ Gracias por el enlace a Rush! No lo había visto todavía. Lo comprobaré esta noche.
@RyanCavanaugh Gracias por la explicación. Tu primer escenario con lerna es el más cercano a lo que tendríamos. Aquí está nuestro repositorio de UX con TS y lerna como ejemplo de algo que nos gustaría usar en el soporte del nuevo proyecto en https://github.com/aurelia/ux
@weswigham Parece que lo que está describiendo también encajaría en nuestro escenario. Repositorio de ejemplo anterior.
Solo tenga en cuenta que en el caso de los espacios de trabajo de hilo, los módulos no están vinculados simbólicamente en el directorio de cada paquete individual, sino que están vinculados simbólicamente en el espacio node_modules
trabajo de nivel superior
Por lo que, dicho sea de paso, creo que las referencias que no comienzan con un punto ('./' o '../') deberían reservarse para el futuro. Con suerte, esos terminarán siendo "referencias con nombre", manejadas a través de la estrategia de resolución del módulo activo en lugar de tratarse como rutas relativas.
@spion solo usaremos un nombre de propiedad que no sea path
para eso si es necesario (por ejemplo, "references": [ { "module": "@foo/baz" } ]
); No quiero causar confusión en la que "bar"
y "./bar"
significan lo mismo en files
pero algo diferente en references
Documentos / publicación de blog en progreso a continuación (se editará en función de los comentarios)
Animaría a cualquiera que siga este hilo a que lo pruebe. Estoy trabajando en el escenario de monorepo ahora para solucionar los últimos errores / características allí y debería tener alguna orientación al respecto pronto
Las referencias de proyectos son una nueva característica de TypeScript 3.0 que le permite estructurar sus programas de TypeScript en partes más pequeñas.
Al hacer esto, puede mejorar en gran medida los tiempos de compilación, hacer cumplir la separación lógica entre componentes y organizar su código de nuevas y mejores formas.
También estamos introduciendo un nuevo modo para tsc
, el indicador --build
, que funciona de la mano con las referencias del proyecto para permitir compilaciones de TypeScript más rápidas.
Veamos un programa bastante normal y veamos cómo las referencias de proyectos pueden ayudarnos a organizarlo mejor.
Imagina que tienes un proyecto con dos módulos, converter
y units
, y un archivo de prueba correspondiente para cada uno:
/src/converter.ts
/src/units.ts
/test/converter-tests.ts
/test/units-tests.ts
/tsconfig.json
Los archivos de prueba importan los archivos de implementación y realizan algunas pruebas:
// converter-tests.ts
import * as converter from "../converter";
assert.areEqual(converter.celsiusToFahrenheit(0), 32);
Anteriormente, era bastante incómodo trabajar con esta estructura si usaba un solo archivo tsconfig:
test
y src
al mismo tiempo sin que apareciera src
en el nombre de la carpeta de salida, lo que probablemente no deseePuede usar varios archivos tsconfig para resolver algunos de esos problemas, pero aparecerían otros nuevos:
tsc
dos vecestsc
dos veces incurre en una mayor sobrecarga de tiempo de iniciotsc -w
no se puede ejecutar en varios archivos de configuración a la vezLas referencias de proyectos pueden resolver todos estos problemas y más.
tsconfig.json
archivos references
. Es una matriz de objetos que especifica proyectos para hacer referencia:
{
"compilerOptions": {
// The usual
},
"references": [
{ "path": "../src" }
]
}
La propiedad path
de cada referencia puede apuntar a un directorio que contiene un archivo tsconfig.json
, o al archivo de configuración en sí (que puede tener cualquier nombre).
Cuando haces referencia a un proyecto, suceden cosas nuevas:
.d.ts
)outFile
, las declaraciones del archivo de salida .d.ts
serán visibles en este proyectoAl dividirse en varios proyectos, puede mejorar en gran medida la velocidad de la verificación de tipos y la compilación, reducir el uso de memoria cuando se utiliza un editor y mejorar la aplicación de las agrupaciones lógicas de su programa.
composite
Los proyectos referenciados deben tener habilitada la nueva configuración composite
.
Esta configuración es necesaria para garantizar que TypeScript pueda determinar rápidamente dónde encontrar las salidas del proyecto al que se hace referencia.
Habilitar la bandera composite
cambia algunas cosas:
rootDir
, si no se establece explícitamente, tiene como valor predeterminado el directorio que contiene el archivo tsconfig
include
o aparecer en la matriz files
. Si se viola esta restricción, tsc
le informará qué archivos no se especificarondeclaration
debe estar encendidodeclarationMaps
También hemos agregado soporte para mapas de fuentes de declaración .
Si habilita --declarationMap
, podrá utilizar funciones del editor como "Ir a la definición" y Cambiar el nombre para navegar y editar el código de forma transparente a través de los límites del proyecto en los editores compatibles.
prepend
con outFile
También puede habilitar anteponer la salida de una dependencia usando la opción prepend
en una referencia:
"references": [
{ "path": "../utils", "prepend": true }
]
Anteponer un proyecto incluirá el resultado del proyecto por encima del resultado del proyecto actual.
Esto funciona tanto para archivos .js
archivos .d.ts
, y los archivos de mapas de origen también se emitirán correctamente.
tsc
solo usará archivos existentes en el disco para realizar este proceso, por lo que es posible crear un proyecto donde no se puede generar un archivo de salida correcto porque la salida de algún proyecto estaría presente más de una vez en el archivo resultante .
Por ejemplo:
^ ^
/ \
B C
^ ^
\ /
D
En esta situación, es importante no anteponer cada referencia, porque terminará con dos copias de A
en la salida de D
; esto puede llevar a resultados inesperados.
Las referencias de proyectos tienen algunas ventajas y desventajas que debe conocer.
Debido a que los proyectos dependientes utilizan archivos .d.ts
que se compilan a partir de sus dependencias, tendrá que verificar ciertos resultados de compilación o compilar un proyecto después de clonarlo antes de poder navegar por el proyecto en un editor sin ver falsos errores.
Estamos trabajando en un proceso de generación de .d.ts detrás de escena que debería poder mitigar esto, pero por ahora recomendamos informar a los desarrolladores que deben compilar después de la clonación.
Además, para preservar la compatibilidad con los flujos de trabajo de compilación existentes, tsc
no creará dependencias automáticamente a menos que se invoque con el conmutador --build
.
Aprendamos más sobre --build
.
Una característica largamente esperada son las compilaciones incrementales inteligentes para proyectos de TypeScript.
En 3.0 puedes usar la bandera --build
con tsc
.
Este es efectivamente un nuevo punto de entrada para tsc
que se comporta más como un orquestador de compilación que como un simple compilador.
Ejecutar tsc --build
( tsc -b
para abreviar) hará lo siguiente:
Puede proporcionar tsc -b
con múltiples rutas de archivo de configuración (por ejemplo, tsc -b src test
).
Al igual que tsc -p
, especificar el nombre del archivo de configuración en sí es innecesario si se llama tsconfig.json
.
tsc -b
Línea Puede especificar cualquier número de archivos de configuración:
> tsc -b # Build the tsconfig.json in the current directory
> tsc -b src # Build src/tsconfig.json
> tsc -b foo/release.tsconfig.json bar # Build foo/release.tsconfig.json and bar/tsconfig.json
No se preocupe por ordenar los archivos que pasa en la línea de comandos: tsc
los reordenará si es necesario para que las dependencias siempre se construyan primero.
También hay algunas banderas específicas para tsc -b
:
--verbose
: Imprime un registro detallado para explicar lo que está sucediendo (se puede combinar con cualquier otra bandera)--dry
: muestra lo que se haría pero en realidad no crea nada--clean
: Elimina las salidas de los proyectos especificados (se puede combinar con --dry
)--force
: Actúe como si todos los proyectos estuvieran desactualizados--watch
: Modo reloj (no se puede combinar con ninguna bandera excepto --verbose
)Normalmente, tsc
producirá salidas ( .js
y .d.ts
) en presencia de errores de sintaxis o tipo, a menos que noEmitOnError
esté activado.
Hacer esto en un sistema de compilación incremental sería muy malo: si una de sus dependencias desactualizadas tuviera un nuevo error, solo lo vería una vez porque una compilación posterior omitiría la compilación del proyecto ahora actualizado.
Por esta razón, tsc -b
actúa efectivamente como si noEmitOnError
estuviera habilitado para todos los proyectos.
Si verifica cualquier salida de compilación ( .js
, .d.ts
, .d.ts.map
, etc.), es posible que deba ejecutar una compilación --force
después de cierto control de fuente operaciones dependiendo de si su herramienta de control de código fuente conserva mapas de tiempo entre la copia local y la copia remota.
Si tiene un proyecto de msbuild, puede activar el modo de compilación agregando
<TypeScriptBuildMode>true</TypeScriptBuildMode>
a su archivo de proyecto. Esto permitirá la construcción incremental automática así como la limpieza.
Tenga en cuenta que, al igual que con tsconfig.json
/ -p
, las propiedades del proyecto TypeScript existente no se respetarán; todas las configuraciones deben administrarse utilizando su archivo tsconfig.
Algunos equipos han configurado flujos de trabajo basados en msbuild en los que los archivos tsconfig tienen el mismo orden de gráficos implícito que los proyectos administrados con los que están emparejados.
Si su solución es así, puede continuar usando msbuild
con tsc -p
junto con las referencias del proyecto; estos son completamente interoperables.
Con más archivos tsconfig.json
, generalmente querrá usar la herencia de archivos de configuración para centralizar las opciones comunes del compilador.
De esta manera, puede cambiar una configuración en un archivo en lugar de tener que editar varios archivos.
Otra buena práctica es tener una "solución" tsconfig.json
archivo que simplemente tiene references
para todos sus proyectos de nodo hoja.
Esto presenta un punto de entrada simple; por ejemplo, en el repositorio de TypeScript simplemente ejecutamos tsc -b src
para construir todos los puntos finales porque enumeramos todos los subproyectos en src/tsconfig.json
Tenga en cuenta que a partir de 3.0, ya no es un error tener una matriz files
vacía si tiene al menos un reference
en un archivo tsconfig.json
.
Puede ver estos patrones en el repositorio de TypeScript; consulte src/tsconfig_base.json
, src/tsconfig.json
y src/tsc/tsconfig.json
como ejemplos clave.
En general, no se necesita mucho para realizar la transición de un repositorio utilizando módulos relativos.
Simplemente coloque un archivo tsconfig.json
en cada subdirectorio de una carpeta principal determinada y agregue reference
s a estos archivos de configuración para que coincidan con las capas previstas del programa.
Deberá establecer outDir
en una subcarpeta explícita de la carpeta de salida, o establecer rootDir
en la raíz común de todas las carpetas del proyecto.
El diseño de las compilaciones que usan outFile
es más flexible porque las rutas relativas no importan tanto.
Una cosa a tener en cuenta es que generalmente no querrá usar prepend
hasta el "último" proyecto; esto mejorará los tiempos de compilación y reducirá la cantidad de E / S necesaria en una compilación determinada.
El repositorio de TypeScript en sí mismo es una buena referencia aquí; tenemos algunos proyectos de "biblioteca" y algunos proyectos de "punto final"; Los proyectos de "endpoint" se mantienen lo más pequeños posible y solo incorporan las bibliotecas que necesitan.
TODO: Experimente más y descubra esto. Rush y Lerna parecen tener diferentes modelos que implican diferentes cosas de nuestra parte.
También busco comentarios sobre # 25164
@RyanCavanaugh Muy buen artículo, y la excelente característica, sería muy bueno probarlo, especialmente. después de pasar días organizando nuestro gran proyecto en subproyectos con referencias de archivos de configuración.
Tengo un par de notas:
gulp watch
y tsc -b -w
en paralelo?@vvs a monorepo es una colección de paquetes de NPM generalmente administrados por una herramienta como Rush o Lerna
Si está usando gulp, querría usar un cargador que entendiera las referencias del proyecto de forma nativa para obtener la mejor experiencia. @rbuckton ha hecho algo de trabajo aquí, ya que tenemos algunos desarrolladores que utilizan un archivo gulp internamente; tal vez pueda opinar sobre cómo se ven los buenos patrones allí
@RyanCavanaugh Esto se ve bien. Estoy muy interesado en la guía de Lerna :)
@RyanCavanaugh esto se ve muy bien, actualmente estoy trabajando para probarlo con nuestra lerna monorepo.
Lo único que no me quedó claro en su escrito fue la opción prepend
. No entendí muy bien qué problema está abordando, en qué situación querría usarlo y qué sucede si no lo usa.
¡Esto es asombroso! Trabajo en ts-loader y proyectos relacionados. ¿Es probable que sean necesarios cambios para respaldar esto en proyectos que usan LanguageServiceHost
/ WatchHost
TypeScript?
(Consulte https://github.com/TypeStrong/ts-loader/blob/master/src/servicesHost.ts para ver un ejemplo de lo que quiero decir).
Si es así, ¡todas las orientaciones / relaciones públicas se reciben con gratitud! De hecho, si desea que esto se pruebe en el mundo de los paquetes web, me complacerá ayudarlo a lanzar una versión de ts-loader que admita esto.
Por supuesto, si "simplemente funciona", es aún mejor: sonríe:
¡Buen trabajo!
@yortus @EisenbergEffect He configurado un repositorio lerna de muestra en https://github.com/RyanCavanaugh/learn-a con un README que describe los pasos que tomé para que funcione.
Si lo entiendo correctamente, tsc -b X
no hará nada si todo (X y todas sus dependencias y dependencias transitivas) está actualizado. ¿Se pregunta si eso es algo que podríamos obtener incluso sin la -b
para proyectos individuales sin referencias? (menos dependencias en ese caso, por supuesto)
Esto está muy bien. Tiendo a usar un Lerna con una configuración como esta (para separar el repositorio mono por función). Supongo que funcionaría igual de bien.
{
"lerna": "2.11.0",
"paquetes": [
"paquetes / componentes / ","paquetes / bibliotecas / ",
"paquetes / frameworks / ","paquetes / aplicaciones / ",
"paquetes / herramientas / *"
],
"versión": "0.0.0"
}
¿Entonces esto está disponible en typescript@next
?
Lo probaré con nuestro repositorio de espacio de trabajo de hilo. Tenemos que usar nohoist
para algunos módulos que aún no admiten espacios de trabajo, por lo que será bueno ver cómo lo maneja.
@RyanCavanaugh Tomé el repositorio para una prueba esta noche. Abrí un problema en el repositorio para informar algunos problemas que tenía. Gracias de nuevo por armar esto. Espero usarlo pronto.
¡Muy interesante! Actualmente, en mi empresa, utilizamos mi propia herramienta llamada mtsc para admitir el modo de visualización de varios proyectos al mismo tiempo. Tenemos alrededor de 5 proyectos que deben compilarse y observarse en el mismo repositorio.
Los proyectos tienen diferentes configuraciones como; Orientación ECMA (es5, es6), tipos (nodo, broma, DOM, etc.), emitir (algunos usan webpack y otros compilan en js). Todos comparten una cosa, y ese es el complemento tslint , el resto puede ser diferente. Mi herramienta también ejecuta tslint después de la compilación de un proyecto (por proyecto y se detiene si un proyecto se vuelve a compilar antes de que tslint finalice).
Mi principal preocupación con la propuesta actual es que no se puede decir qué proyectos comparten qué recursos. Tenemos un proyecto de servidor y cliente, que ambos usan una carpeta de utilidad especial, pero que no queremos ver los errores de compilación de dos veces. Pero eso se puede arreglar con un filtro, así que no es gran cosa :)
Probé el nuevo modo --build
con nuestro lerna monorepo, que actualmente consta de 17 paquetes interdependientes. Tomó un tiempo hacer que todo funcionara, pero ahora todo funciona, y poder construir de forma incremental es una gran mejora para nosotros.
Encontré algunos problemas que describo a continuación. Espero que esta sea una retroalimentación útil para el equipo de TS y pueda ayudar a otros a conseguir que el modo --build
funcione para sus proyectos.
tsc --build
Recibí este mensaje para cada paquete en cada compilación, por lo que cada compilación se convirtió en una reconstrucción completa incluso cuando no se cambió nada. Me di cuenta de que @RyanCavanaugh ya ha solucionado esto en # 25281, por lo que ya no es un problema si actualiza a 20180628
o más tarde todas las noches. Los siguientes problemas asumen que ha actualizado al menos a 20180628
noche.
EDITAR: informado en # 25337.
Para reproducir este problema, configure @RyanCavanaugh 's learn-a
cesión temporal de la muestra según sus instrucciones . Ejecute tsc -b packages --verbose
para ver que todo se construye la primera vez. Ahora cambie la línea 1 en pkg1/src/index.ts
a import {} from "./foo";
y guárdelo. Ejecute tsc -b packages --verbose
nuevamente. La compilación para pkg2
se omite, aunque pkg1
se modificó de una manera que rompe el código fuente de pkg2
. Ahora puede ver un garabato rojo en pkg2/src/index.ts
. Vuelva a compilar con tsc -b packages --force
y se muestra el error de compilación. Los siguientes problemas asumen la construcción con --force
para solucionar este problema.
.d.ts
que causaron errores de compilación de "identificador duplicado" en los paquetes posteriores.EDITAR: informado en # 25338.
Para reproducir este problema, configure @RyanCavanaugh 's learn-a
cesión temporal de la muestra según sus instrucciones . Ahora ejecute lerna add @types/node
para agregar tipificaciones de Node.js a los tres paquetes. Ejecute tsc -b packages --force
para confirmar que aún se compila bien. Ahora agregue el siguiente código a pkg1/src/index.ts
:
// CASE1 - no build errors in pkg1, but 'duplicate identifier' build errors in pkg2
// import {parse} from 'url';
// export const bar = () => parse('bar');
// CASE2 - no build errors in pkg1 or in downstream packages
// import {parse, UrlWithStringQuery} from 'url';
// export const bar = (): UrlWithStringQuery => parse('bar');
// CASE3 - no build errors in pkg1 or in downstream packages
// export declare const bar: () => import("url").UrlWithStringQuery;
// CASE4 - no build errors in pkg1, but 'duplicate identifier' build errors in pkg2
// import {parse} from 'url';
// type UrlWithStringQuery = import("url").UrlWithStringQuery;
// export const bar = (): UrlWithStringQuery => parse('bar');
Descomente un caso a la vez y ejecute tsc -b packages --force
. Los casos 1 y 4 provocan una avalancha de errores de compilación en pkg2
. Con los casos 2 y 3, no hay errores de compilación. La diferencia importante con los casos 1 y 4 parece ser la primera línea en el pkg1/lib/index.d.ts
generado:
/// <reference path="../node_modules/@types/node/index.d.ts" />
Los casos 2 y 3 no generan esta línea. Cuando se construye pkg2
en los casos 1 y 4, incluye dos copias idénticas de declaraciones @types/node
en diferentes rutas, y eso provoca los errores de 'identificador duplicado'.
Quizás esto sea por diseño, ya que los casos 2 y 3 funcionan. Sin embargo, parece bastante confuso. No hay errores de compilación ni advertencias en pkg1
para ninguno de estos 4 casos, pero el comportamiento de compilación posterior es muy sensible al estilo exacto de las declaraciones exportadas. Creo que (a) pkg1
debería generar un error para los casos 1 y 4, o (b) los cuatro casos deberían tener el mismo comportamiento de compilación posterior, o (c) debería haber una guía clara del equipo de TS sobre cómo escribir declaraciones para evitar este problema.
import
tipos en generadas .d.ts
archivos cuando se utilizan los espacios de trabajo de hiloAl tratar de obtener trabajo modo de construcción con nuestro paquete de 17 monorepo, trabajé a través de una serie de errores de generación causados por las rutas relativas en import
tipos en generadas .d.ts
archivos. Finalmente resolví que el problema estaba relacionado con la elevación del módulo. Es decir, cuando se utilizan espacios de trabajo de hilo, todos los módulos instalados se elevan al directorio monorepo-root node_modules
, incluidos los enlaces simbólicos para todos los paquetes del monorepo. Cambié el monorepo para usar la propiedad packages
en lerna.json
, lo que hace que lerna
use su propio algoritmo de arranque sin elevación, y eso resolvió el problema. De todos modos, es un enfoque mejor / más seguro, aunque más lento.
No estoy seguro de si TS tiene la intención de admitir configuraciones de módulos, por lo que no he desarrollado una reproducción para los problemas que encontré, pero podría intentar hacer una si hay interés. Creo que el problema puede ser que algunas compilaciones obtienen el mismo tipo a través del directorio de nivel superior packages
(según la configuración de tsconfig) y el directorio de nivel superior node_modules
(según import
tipos en archivos .d.ts
generados). Esto a veces funciona debido a la escritura estructural, pero falla para cosas como símbolos únicos exportados.
Configurar un monorepo para usar lerna básicamente solo requiere poner algo como "packages": ["packages/*"]
en lerna.json
. Lerna calcula la lista exacta de paquetes expandiendo globstars y luego calcula el gráfico de dependencia exacto observando las dependencias declaradas en el package.json
cada paquete. Puede agregar y eliminar paquetes y dependencias a voluntad, y lerna
mantiene al día sin necesidad de tocar su configuración.
El modo TypeScript --build
implica un poco más de ceremonia. Los patrones globales no se reconocen, por lo que todos los paquetes deben enumerarse y mantenerse explícitamente (por ejemplo, en packages/tsconfig.json
) en el repositorio de learn-a
@RyanCavanaugh. El modo de compilación no tiene en cuenta las dependencias package.json
, por lo que cada paquete debe mantener la lista de otros paquetes de los que depende tanto en su archivo package.json
(bajo "dependencies"
) como es tsconfig.json
archivo (menos de "references"
).
Este es un inconveniente menor, pero lo incluyo aquí ya que encontré el galimatías notable en comparación con el enfoque lerna's
.
tsc
con aumentos de módulo globalesEDITAR: informado en # 25339.
Para reproducir este problema, configure @RyanCavanaugh 's learn-a
repo muestra de acuerdo con sus instrucciones . Ahora ejecute lerna add @types/multer
para agregar multer
mecanografía a los tres paquetes. Ejecute tsc -b packages --force
para confirmar que aún se compila bien. Ahora agregue la siguiente línea a pkg1/src/index.ts
:
export {Options} from 'multer';
Ejecute tsc -b packages --force
nuevamente. El compilador falla debido a una aserción violada. Miré brevemente el seguimiento y la aserción de la pila, y parece que tiene algo que ver con el aumento global del espacio Express
nombres
gracias @yortus por los comentarios. confiar en apreciarlo. para 3, creo que es https://github.com/Microsoft/TypeScript/issues/25278.
Para 4, no estoy familiarizado con la elevación de módulos como concepto. ¿Puedes elaborar y / o compartir una reproducción?
@mhegazy muchos de los que usan lerna y yarn usan espacios de trabajo (incluyéndome a mí). Más información aquí: https://yarnpkg.com/lang/en/docs/workspaces/
Actualmente estoy usando espacios de trabajo de hilo, lerna, tsconfigs extendidos donde el tsconfig base declara paths
compartido para todos los paquetes con el módulo elevado que se encuentra en root/node_modules
. Cuando escucho yarn
y monorepo
, pienso workspaces
porque esa es la intención de la función: facilitar el uso y reducir la duplicación. Esperaba que este cambio simplemente eliminara mi largo / doloroso paths
declarado en mi tsconfig base.
Aquí hay una muestra de nuestro tsconfig raíz monorepo (si es de alguna ayuda):
{
"extends": "./packages/build/tsconfig.base.json",
"compilerOptions": {
"baseUrl": "./packages",
"paths": {
"@alienfast/build/*": ["./build/src/*"],
"@alienfast/common-node/*": ["./common-node/src/*"],
"@alienfast/common/*": ["./common/src/*"],
"@alienfast/concepts/*": ["./concepts/src/*"],
"@alienfast/faas/*": ["./faas/src/*"],
"@alienfast/math/*": ["./math/src/*"],
"@alienfast/notifications/*": ["./notifications/src/*"],
"@alienfast/ui/*": ["./ui/src/*"],
"@alienfast/build": ["./build/src"],
"@alienfast/common-node": ["./common-node/src"],
"@alienfast/common": ["./common/src"],
"@alienfast/concepts": ["./concepts/src"],
"@alienfast/faas": ["./faas/src"],
"@alienfast/math": ["./math/src"],
"@alienfast/notifications": ["./notifications/src"],
"@alienfast/ui": ["./ui/src"],
}
},
"include": ["./typings/**/*", "./packages/*/src/**/*"],
"exclude": ["node_modules", "./packages/*/node_modules"]
}
Intentaré bifurcar una muestra:
https://github.com/RyanCavanaugh/learn-a
Aquí hay un PR no para fusionar al repositorio de
https://github.com/RyanCavanaugh/learn-a/pull/3/files
También utilizamos izado de módulos en Jupyterlab , con lerna e hilo. Nos permite compartir básicamente nuestras dependencias instaladas entre todos nuestros paquetes, por lo que solo existen una vez en el sistema de archivos, en el proyecto raíz.
Entiendo que los espacios de trabajo son un poco más limpios que tener que usar el comando link
entre todos los paquetes para que puedan acceder entre sí (o al menos acceder a sus dependencias).
Como se indicó anteriormente, la elevación de módulos mueve todas las dependencias a un directorio raíz node_modules
. Esto aprovecha el hecho de que la resolución del módulo de nodo siempre recorrerá el árbol de directorios y buscará en todos los directorios node_modules
hasta que encuentre el módulo requerido. Los módulos individuales en su monorepo se enlazan simbólicamente en esta raíz node_modules
y todo simplemente funciona. La publicación del blog de hilo probablemente lo explica mejor que yo.
No se garantiza que ocurra el izado. Si tiene versiones no coincidentes del mismo paquete, no se levantarán. Además, muchas herramientas existentes no admiten la elevación porque hacen suposiciones sobre dónde estará node_modules
o no siguen correctamente la resolución del módulo de nodo. Debido a esto, hay una configuración nohoist
que puede deshabilitar la elevación para módulos o dependencias específicas.
Agregué un sexto elemento a mis comentarios anteriores . tsc
bloquea en el escenario que se describe allí.
@mhegazy No estoy seguro de que el elemento 3 esté relacionado con # 25278. # 25278 describe la emisión de declaración no válida. Mis archivos de declaración generados eran sintácticamente y semánticamente válidos, pero causaron que los proyectos posteriores se construyeran con dos copias de mecanografía de nodos, lo que resultó en errores de 'identificador duplicado'.
Como se indicó anteriormente, la elevación de módulos mueve todas las dependencias a un directorio raíz node_modules. Esto aprovecha el hecho de que la resolución del módulo de nodo siempre recorrerá el árbol de directorios y buscará en todos los directorios de node_modules hasta que encuentre el módulo requerido.
Por cierto, hay una desventaja de este modelo, que conduce a "dependencias fantasma" donde un proyecto puede importar una dependencia que no fue declarada explícitamente en su archivo package.json. Cuando publica su biblioteca, esto puede causar problemas, como (1) que se instale una versión diferente de la dependencia que la que se probó / esperada, o (2) la dependencia falta por completo porque se obtuvo de un proyecto no relacionado que no está instalado en este contexto. PNPM y Rush tienen opciones arquitectónicas destinadas a proteger contra dependencias fantasma.
Tengo una pregunta general sobre tsc --build
: ¿El compilador de TypeScript busca asumir el papel de orquestar la compilación para proyectos en un monorepo? Normalmente, la cadena de herramientas tendrá toda una serie de tareas, cosas como:
Normalmente, un sistema como Gulp o Webpack gestiona esta canalización, y el compilador es solo un paso en el medio de la cadena. A veces, una herramienta secundaria también ejecuta la compilación de otra manera, por ejemplo, Jest + ts-jest por jest --watch
.
¿ tsc
tiene como objetivo gestionar estas cosas por sí mismo? Y si no es así, ¿hay alguna manera de que un orquestador de compilación convencional resuelva el gráfico de dependencia en sí mismo y, por ejemplo, invoque tsc repetidamente en cada carpeta de proyecto en el orden correcto (después de que se haya actualizado el preprocesamiento)?
O, si el diseño es procesar un monorepo completo en una sola pasada (mientras que hoy construimos cada proyecto en un proceso de NodeJs separado), también tengo curiosidad por saber cómo participarán las otras tareas de compilación: por ejemplo, ¿ejecutaremos webpack en todos los proyectos a la vez? (En el pasado, eso provocó problemas de falta de memoria). ¿Perderemos la capacidad de aprovechar la concurrencia de múltiples procesos?
Estas no son críticas por cierto. Solo estoy tratando de comprender el panorama general y el uso previsto.
@pgonzal correcto, hay muchas partes que no son de tsc para construir un monorepo del mundo real. Para nuestra lerna monorepo, tomé el siguiente enfoque:
prebuild
y / o un script postbuild
en su package.json
. Estos contienen los aspectos de la compilación que no son tsc.package.json
del monorepo, hay estos scripts:
"prebuild": "lerna run prebuild",
"build": "tsc --build monorepo.tsconfig.json --verbose",
"postbuild": "lerna run postbuild",
yarn build
en el nivel de monorepo ejecuta los scripts prebuild
para cada paquete que los define, luego ejecuta el paso tsc --build
, luego ejecuta todos los postbuild
guiones. (Por convención tanto en npm como en yarn, ejecutar npm run foo
es aproximadamente lo mismo que npm run prefoo && npm run foo && npm run postfoo
.)¿Cómo maneja jest --watch
o webpack-dev-server
? Por ejemplo, cuando se modifica un archivo de origen, ¿se vuelven a ejecutar los pasos previos y posteriores a la compilación?
¿Tiene esto alguna implicación en ts-node
y los flujos de trabajo relacionados? Algunas de nuestras aplicaciones de ayuda se ejecutan "directamente" desde TypeScript, como "start": "ts-node ./src/app.ts"
o "start:debug": "node -r ts-node/register --inspect-brk ./src/app.ts"
.
Se informó otro problema con el modo de compilación en # 25355.
Gracias por todos los excelentes comentarios e investigaciones hasta ahora. Realmente aprecio a todos los que se tomaron el tiempo para probar cosas y patear los neumáticos.
@yortus re https://github.com/Microsoft/TypeScript/issues/3469#issuecomment -400439520
Excelente reseña, gracias de nuevo por proporcionarnos esto. Tus problemas en orden -
--build
AFAICT. Esta es una nueva afirmación que agregamos recientemente; Nathan está investigando@rosskevin 🎉 para el PR en el repositorio learn-a
! Voy a fusionar eso en una rama para que podamos comparar y contrastar mejor.
@pgonzal re https://github.com/Microsoft/TypeScript/issues/3469#issuecomment -401577442
Tengo una pregunta general sobre tsc --build: ¿el compilador de TypeScript busca asumir el rol de orquestar la compilación para proyectos en un monorepo?
Gran pregunta; Quiero responder a esta muy claramente: definitivamente no .
Si está contento hoy usando tsc
para construir su proyecto, queremos que sea feliz mañana usando tsc -b
para construir su proyecto de varias partes. Si está contento hoy usando gulp
para construir su proyecto, queremos que sea feliz mañana usando gulp
para construir su proyecto de varias partes. Tenemos control sobre el primer escenario, pero necesitamos autores de herramientas y complementos que nos ayuden con el segundo, por lo que incluso tsc -b
es solo una envoltura delgada sobre las API expuestas que los autores de herramientas pueden usar para ayudar a que las referencias de proyectos funcionen bien. en sus modelos de construcción.
El contexto más amplio es que hubo un debate interno bastante sólido sobre si tsc -b
debería existir, o en su lugar ser una herramienta / punto de entrada separado: construir un orquestador de compilación de propósito general es una tarea enorme y no una de las que estamos registrarse para. Para nuestro propio repositorio usamos tsc
con un marco de ejecución de tareas liviano y ahora usamos tsc -b
con el mismo ejecutor de tareas, y esperaría que cualquier otra persona que migre también mantenga su cadena de compilación existente en su lugar con solo pequeños retoques.
@borekb re https://github.com/Microsoft/TypeScript/issues/3469#issuecomment -401593804
¿Tiene esto alguna implicación en ts-node y los flujos de trabajo relacionados? Algunas de nuestras aplicaciones de ayuda se ejecutan "directamente" desde TypeScript
Para los scripts de un solo archivo, que implícitamente no pueden tener referencias de proyecto, no hay impacto.
@EisenbergEffect tuvo algunas preguntas en el repositorio learn-a
sobre el cambio de nombre entre proyectos y otras características del servicio de idiomas. La gran pregunta abierta aquí es si podremos obtener esta función en un estado utilizable para 3.0 o no. Si es así, entonces el cambio de nombre entre proyectos "simplemente funcionará", sujeto a la advertencia de que obviamente es imposible para nosotros encontrar de manera concluyente todos los proyectos posteriores y actualizarlos; este será un "mejor esfuerzo" basado en algunas heurísticas para buscar otros proyectos.
Si no creemos que el cambio de nombre entre proyectos sea aceptablemente estable + completo para 3.0, es probable que bloqueemos las operaciones de cambio de nombre solo cuando el símbolo renombrado esté en el archivo de salida .d.ts de otro proyecto; permitirle hacer esto sería muy confuso porque el archivo .d.ts se actualizaría en una compilación posterior del proyecto ascendente después de que se modificó el proyecto ascendente, lo que significa que podrían pasar días entre el momento en que realiza un cambio de nombre local y el momento en que se da cuenta de que el código de declaración en realidad no se había actualizado.
Para características como Ir a la definición, estas están funcionando hoy en VS Code y funcionarán listas para usar en futuras versiones de Visual Studio. Todas estas funciones requieren que los archivos .d.ts.map estén habilitados (active declarationMap
). Hay un trabajo por función para iluminar esto, por lo que si ve que algo no funciona como se esperaba, registre un error, ya que es posible que nos hayamos perdido algunos casos.
Problemas abiertos que estoy rastreando en este punto:
learn-a
que use yarn
, y otra que use pnpm
, y otra que use uno de esos en modo elevadoPreguntas abiertas
package.json
s para inferir las referencias del proyecto? Registrado # 25376.d.ts.map
estar implícitamente activada para proyectos composite
?@RyanCavanaugh para agregar a
Problemas abiertos que estoy rastreando en este momento
También mencionamos tener una caché de salida incremental, separada de la ubicación de salida real del proyecto, para manejar cosas como actualizar las declaraciones en segundo plano en el LS (hoy, los cambios no se propagan a través de los límites del proyecto en el editor hasta que se crea), stripInternal
, y procesos de compilación mutantes (donde nuestras salidas de compilación están mutadas en su lugar y, por lo tanto, no son adecuadas para las operaciones de LS).
perdón por una pregunta tonta, ya que está marcada en la hoja de ruta, ¿cómo habilito esta función?
@ aleksey-bykov puede usarlo en mecanografiado @ next.
Probé esto en nuestro monorepo impulsado por el espacio de trabajo de hilo y funciona bien.
Una cosa que noté fue que tsc --build --watch
reporta errores pero luego no muestra nada para decir que la compilación ahora está arreglada. El modo de vigilancia estándar tsc
en 2.9 ha comenzado a dar un recuento de errores y es bueno ver un cero allí para que sepa que la construcción se ha completado.
tengo una carpeta llena de * .d.ts y nada más, ¿qué se supone que debo hacer al respecto?
@timfish que los comentarios coinciden con otros que he escuchado; registrado # 25562
@ aleksey-bykov https://github.com/Microsoft/TypeScript/issues/3469#issuecomment -400439520 debería ayudar a explicar algunos conceptos
@RyanCavanaugh parece que la referencia del proyecto solo funciona para commonjs y la resolución del módulo de nodo, ¿no es así?
en tu ejemplo:
import * as p1 from "@ryancavanaugh/pkg1";
import * as p2 from "@ryancavanaugh/pkg2";
p1.fn();
p2.fn4();
@ryancavanaugh
¿Tiene algo que ver con la forma en que TS resuelve los módulos?outFile
para encontrar las definiciones?tengo 2 proyectos simples essentials
y common
y las cosas en común no pueden resolver las cosas compiladas en Essentials:
@ aleksey-bykov
Si tiene un repositorio de muestra o algo, puedo diagnosticar por qué está recibiendo ese error
@RyanCavanaugh por favor hazlo
ejemplo.zip
@RyanCavanaugh , también parece que tsc --build --watch
inicialmente no genera ningún archivo hasta que ve una modificación de un archivo fuente.
Hilo demasiado largo (tanto en el tiempo como en el espacio); retomemos la discusión en el número de la suerte 100 * 2 ^ 8: # 25600
Comentario más útil
Documentos / publicación de blog en progreso a continuación (se editará en función de los comentarios)
Animaría a cualquiera que siga este hilo a que lo pruebe. Estoy trabajando en el escenario de monorepo ahora para solucionar los últimos errores / características allí y debería tener alguna orientación al respecto pronto
Referencias de proyectos
Las referencias de proyectos son una nueva característica de TypeScript 3.0 que le permite estructurar sus programas de TypeScript en partes más pequeñas.
Al hacer esto, puede mejorar en gran medida los tiempos de compilación, hacer cumplir la separación lógica entre componentes y organizar su código de nuevas y mejores formas.
También estamos introduciendo un nuevo modo para
tsc
, el indicador--build
, que funciona de la mano con las referencias del proyecto para permitir compilaciones de TypeScript más rápidas.Un proyecto de ejemplo
Veamos un programa bastante normal y veamos cómo las referencias de proyectos pueden ayudarnos a organizarlo mejor.
Imagina que tienes un proyecto con dos módulos,
converter
yunits
, y un archivo de prueba correspondiente para cada uno:Los archivos de prueba importan los archivos de implementación y realizan algunas pruebas:
Anteriormente, era bastante incómodo trabajar con esta estructura si usaba un solo archivo tsconfig:
test
ysrc
al mismo tiempo sin que aparecierasrc
en el nombre de la carpeta de salida, lo que probablemente no deseePuede usar varios archivos tsconfig para resolver algunos de esos problemas, pero aparecerían otros nuevos:
tsc
dos vecestsc
dos veces incurre en una mayor sobrecarga de tiempo de iniciotsc -w
no se puede ejecutar en varios archivos de configuración a la vezLas referencias de proyectos pueden resolver todos estos problemas y más.
¿Qué es una referencia de proyecto?
tsconfig.json
archivosreferences
. Es una matriz de objetos que especifica proyectos para hacer referencia:La propiedad
path
de cada referencia puede apuntar a un directorio que contiene un archivotsconfig.json
, o al archivo de configuración en sí (que puede tener cualquier nombre).Cuando haces referencia a un proyecto, suceden cosas nuevas:
.d.ts
)outFile
, las declaraciones del archivo de salida.d.ts
serán visibles en este proyectoAl dividirse en varios proyectos, puede mejorar en gran medida la velocidad de la verificación de tipos y la compilación, reducir el uso de memoria cuando se utiliza un editor y mejorar la aplicación de las agrupaciones lógicas de su programa.
composite
Los proyectos referenciados deben tener habilitada la nueva configuración
composite
.Esta configuración es necesaria para garantizar que TypeScript pueda determinar rápidamente dónde encontrar las salidas del proyecto al que se hace referencia.
Habilitar la bandera
composite
cambia algunas cosas:rootDir
, si no se establece explícitamente, tiene como valor predeterminado el directorio que contiene el archivotsconfig
include
o aparecer en la matrizfiles
. Si se viola esta restricción,tsc
le informará qué archivos no se especificarondeclaration
debe estar encendidodeclarationMaps
También hemos agregado soporte para mapas de fuentes de declaración .
Si habilita
--declarationMap
, podrá utilizar funciones del editor como "Ir a la definición" y Cambiar el nombre para navegar y editar el código de forma transparente a través de los límites del proyecto en los editores compatibles.prepend
conoutFile
También puede habilitar anteponer la salida de una dependencia usando la opción
prepend
en una referencia:Anteponer un proyecto incluirá el resultado del proyecto por encima del resultado del proyecto actual.
Esto funciona tanto para archivos
.js
archivos.d.ts
, y los archivos de mapas de origen también se emitirán correctamente.tsc
solo usará archivos existentes en el disco para realizar este proceso, por lo que es posible crear un proyecto donde no se puede generar un archivo de salida correcto porque la salida de algún proyecto estaría presente más de una vez en el archivo resultante .Por ejemplo:
En esta situación, es importante no anteponer cada referencia, porque terminará con dos copias de
A
en la salida deD
; esto puede llevar a resultados inesperados.Advertencias para las referencias de proyectos
Las referencias de proyectos tienen algunas ventajas y desventajas que debe conocer.
Debido a que los proyectos dependientes utilizan archivos
.d.ts
que se compilan a partir de sus dependencias, tendrá que verificar ciertos resultados de compilación o compilar un proyecto después de clonarlo antes de poder navegar por el proyecto en un editor sin ver falsos errores.Estamos trabajando en un proceso de generación de .d.ts detrás de escena que debería poder mitigar esto, pero por ahora recomendamos informar a los desarrolladores que deben compilar después de la clonación.
Además, para preservar la compatibilidad con los flujos de trabajo de compilación existentes,
tsc
no creará dependencias automáticamente a menos que se invoque con el conmutador--build
.Aprendamos más sobre
--build
.Modo de compilación para TypeScript
Una característica largamente esperada son las compilaciones incrementales inteligentes para proyectos de TypeScript.
En 3.0 puedes usar la bandera
--build
contsc
.Este es efectivamente un nuevo punto de entrada para
tsc
que se comporta más como un orquestador de compilación que como un simple compilador.Ejecutar
tsc --build
(tsc -b
para abreviar) hará lo siguiente:Puede proporcionar
tsc -b
con múltiples rutas de archivo de configuración (por ejemplo,tsc -b src test
).Al igual que
tsc -p
, especificar el nombre del archivo de configuración en sí es innecesario si se llamatsconfig.json
.tsc -b
LíneaPuede especificar cualquier número de archivos de configuración:
No se preocupe por ordenar los archivos que pasa en la línea de comandos:
tsc
los reordenará si es necesario para que las dependencias siempre se construyan primero.También hay algunas banderas específicas para
tsc -b
:--verbose
: Imprime un registro detallado para explicar lo que está sucediendo (se puede combinar con cualquier otra bandera)--dry
: muestra lo que se haría pero en realidad no crea nada--clean
: Elimina las salidas de los proyectos especificados (se puede combinar con--dry
)--force
: Actúe como si todos los proyectos estuvieran desactualizados--watch
: Modo reloj (no se puede combinar con ninguna bandera excepto--verbose
)Advertencias
Normalmente,
tsc
producirá salidas (.js
y.d.ts
) en presencia de errores de sintaxis o tipo, a menos quenoEmitOnError
esté activado.Hacer esto en un sistema de compilación incremental sería muy malo: si una de sus dependencias desactualizadas tuviera un nuevo error, solo lo vería una vez porque una compilación posterior omitiría la compilación del proyecto ahora actualizado.
Por esta razón,
tsc -b
actúa efectivamente como sinoEmitOnError
estuviera habilitado para todos los proyectos.Si verifica cualquier salida de compilación (
.js
,.d.ts
,.d.ts.map
, etc.), es posible que deba ejecutar una compilación--force
después de cierto control de fuente operaciones dependiendo de si su herramienta de control de código fuente conserva mapas de tiempo entre la copia local y la copia remota.msbuild
Si tiene un proyecto de msbuild, puede activar el modo de compilación agregando
a su archivo de proyecto. Esto permitirá la construcción incremental automática así como la limpieza.
Tenga en cuenta que, al igual que con
tsconfig.json
/-p
, las propiedades del proyecto TypeScript existente no se respetarán; todas las configuraciones deben administrarse utilizando su archivo tsconfig.Algunos equipos han configurado flujos de trabajo basados en msbuild en los que los archivos tsconfig tienen el mismo orden de gráficos implícito que los proyectos administrados con los que están emparejados.
Si su solución es así, puede continuar usando
msbuild
contsc -p
junto con las referencias del proyecto; estos son completamente interoperables.Guia
Estructura general
Con más archivos
tsconfig.json
, generalmente querrá usar la herencia de archivos de configuración para centralizar las opciones comunes del compilador.De esta manera, puede cambiar una configuración en un archivo en lugar de tener que editar varios archivos.
Otra buena práctica es tener una "solución"
tsconfig.json
archivo que simplemente tienereferences
para todos sus proyectos de nodo hoja.Esto presenta un punto de entrada simple; por ejemplo, en el repositorio de TypeScript simplemente ejecutamos
tsc -b src
para construir todos los puntos finales porque enumeramos todos los subproyectos ensrc/tsconfig.json
Tenga en cuenta que a partir de 3.0, ya no es un error tener una matriz
files
vacía si tiene al menos unreference
en un archivotsconfig.json
.Puede ver estos patrones en el repositorio de TypeScript; consulte
src/tsconfig_base.json
,src/tsconfig.json
ysrc/tsc/tsconfig.json
como ejemplos clave.Estructuración de módulos relativos
En general, no se necesita mucho para realizar la transición de un repositorio utilizando módulos relativos.
Simplemente coloque un archivo
tsconfig.json
en cada subdirectorio de una carpeta principal determinada y agreguereference
s a estos archivos de configuración para que coincidan con las capas previstas del programa.Deberá establecer
outDir
en una subcarpeta explícita de la carpeta de salida, o establecerrootDir
en la raíz común de todas las carpetas del proyecto.Estructuración para outFiles
El diseño de las compilaciones que usan
outFile
es más flexible porque las rutas relativas no importan tanto.Una cosa a tener en cuenta es que generalmente no querrá usar
prepend
hasta el "último" proyecto; esto mejorará los tiempos de compilación y reducirá la cantidad de E / S necesaria en una compilación determinada.El repositorio de TypeScript en sí mismo es una buena referencia aquí; tenemos algunos proyectos de "biblioteca" y algunos proyectos de "punto final"; Los proyectos de "endpoint" se mantienen lo más pequeños posible y solo incorporan las bibliotecas que necesitan.
Estructuración para monorepos
TODO: Experimente más y descubra esto. Rush y Lerna parecen tener diferentes modelos que implican diferentes cosas de nuestra parte.