Модули и пространства имен: Каков правильный способ организации большого проекта typescript?
Я новичок в typescript, и я пишу небольшую основу для создания прототипов для WebGl. В настоящее время я реорганизую свой проект и сталкиваюсь с некоторыми проблемами, как организовать мой проект, поскольку оба подхода (модули и пространства имен), похоже, имеют серьезные недостатки.
Этот пост не о том, КАК использовать эти шаблоны, но как преодолеть проблемы, которые каждый из них приносит.
Status Quo: использование пространств имен
Из С# это казалось самым естественным способом. Каждый класс/модуль получает соответствующее пространство имён, и я предоставляю параметр "outFile" в tsconfig.json, поэтому все конкатенируется в один большой файл.
После компиляции у меня есть мое корневое пространство имен как глобальный объект. Зависимости не встроены в проект, поэтому вам необходимо вручную предоставить необходимые *.js файлы в html (не хорошо)
Пример файла
namespace Cross.Eye {
export class SpriteFont {
//code omitted
}
}
Пример использования (вы должны убедиться, что пространство имен Cross загружено в глобальное пространство имен, прежде чем отправить файл js в html)
namespace Examples {
export class _01_BasicQuad {
context: Cross.Eye.Context;
shader: Cross.Eye.ShaderProgram;
//code omitted
}
}
Pros
- Прямо для использования, если вы отправляетесь с С#/Java
- Независимо от имени файла - переименование файлов не нарушит ваш код.
- Простота рефакторинга: IDE могут легко переименовать пространства имен/классы, и изменения будут применяться последовательно для вашего кода.
- Удобство. Добавление класса в проект так же просто, как добавление файла и объявление его в нужном пространстве имен.
Против
Для большинства проектов мы рекомендуем использовать внешние модули и использовать пространство имен для быстрых демонстраций и портирования старого кода JavaScript.
из https://basarat.gitbooks.io/typescript/content/docs/project/namespaces.html
- Корневое пространство имен всегда (?) - глобальный объект (плохой)
- Невозможно (?) использовать такие инструменты, как browserify или webpack, что необходимо для связывания lib с его зависимостями или связывания вашего пользовательского кода с lib при его фактическом использовании.
- Плохая практика, если вы планируете выпустить модуль npm
Уровень техники (?): Модули
Typescript поддерживает модули ES6, они новые и блестящие, и все, похоже, согласны с тем, что они - путь. Идея состоит в том, что каждый файл является модулем, и, подавая файлы в операторах импорта, вы можете четко определить свои зависимости, что упрощает сбор инструментов для эффективного пакета кода. У меня в основном есть один класс для каждого файла, который, похоже, не работает с шаблоном модуля dhte.
Это моя файловая структура после рефакторе:
![enter image description here]()
Также у меня есть файл index.ts в каждой папке, поэтому я могу импортировать все его классы import * as FolderModule from "./folder"
export * from "./AggregateLoader";
export * from "./ImageLoader";
export * from "./TiledLoader";
export * from "./XhrLoaders";
export * from "./XmlSpriteFontLoader";
Пример файла - я думаю, проблема становится ясно видна здесь.
import {SpriteFont} from "./SpriteFont";
import {ISpriteTextGlyph, ISpriteChar} from "./Interfaces";
import {Event,EventArgs} from "../../Core";
import {Attribute, AttributeConfiguration} from "../Attributes";
import {DataType} from "../GlEnums";
import {VertexStore} from "../VertexStore";
import {IRectangle} from "../Geometry";
import {vec3} from "gl-matrix";
export class SpriteText {
// code omitted
}
Пример использования. Как вы можете видеть, мне больше не нужно проходить через пространства имен, потому что я могу напрямую импортировать классы.
import {
Context,
Shader,
ShaderProgram,
Attribute,
AttributeConfiguration,
VertexStore,
ShaderType,
VertexBuffer,
PrimitiveType
} from "../cross/src/Eye";
import {
Assets,
TextLoader
} from "../cross/src/Load";
export class _01_BasicQuad {
context: Context;
shader: ShaderProgram;
// code omitted.
}
Pros
- Делает ваш код более модульным, поскольку он больше не привязан к пространствам имен.
- Вы можете использовать инструменты для объединения, такие как browserfy или webpack, которые также могут связывать все ваши зависимости
- Вы более гибки при импорте классов и больше не должны перемещаться по цепочкам пространства имен.
Против
- Очень утомительно, если каждый класс является другим файлом, вам придется вводить одни и те же операторы импорта снова и снова.
- Переименование файлов нарушит ваш код (плохой).
- Имена классов рефакторинга не будут распространяться на ваш импорт (очень плохо - может зависеть от вашей среды IDE, но я использую vs-code)
ИМО оба подхода кажутся ошибочными. Пространства имен кажутся ужасно устаревшими, непрактичными для больших проектов и несовместимыми с общими инструментами при использовании модулей, являются довольно неудобными и ломают некоторые из возможностей, которые я адаптировал для typescript в первую очередь.
В идеальном мире я бы написал свою фреймворк с использованием шаблона пространства имен и экспортировал его как модуль, который затем можно импортировать и связывать с его зависимостями. Однако это не представляется возможным без каких-либо уродливых хаков.
Итак, вот мой вопрос: как вы справлялись с этими проблемами? Как можно свести к минимуму недостатки, которые подразумевает каждый подход?
Update
Получив немного больше опыта разработки typescript и javascript в целом, я должен указать, что модули, вероятно, подходят для 90% всех случаев использования.
Последние 10%, как мы надеемся, являются устаревшими проектами, использующими глобальные пространства имен, которые вы хотите оживить с помощью небольшого typescript (который отлично работает, кстати).
Большая часть моего критика для модулей может быть (и была) решена благодаря лучшей поддержке IDE. Visual Studio Code с тех пор добавляет автоматическое разрешение модуля, которое отлично работает.
Ответы
Ответ 1
tl; dr: Не выбирайте прошлое. Выберите будущее: Модули.
В ранних проектах спецификации модулей ES6 существовало понятие встроенных модулей, которое затем была выпущена в июле 2014 года без встроенных модулей. Год спустя, в июле 2015 года, с версией 1.5 из TypeScript, внутренние модули были переименованы в пространства имен во избежание путаницы со стандартом.
Пространства имен являются устаревшей функцией. Он не будет частью языка ECMAScript. И команда TypeScript будет продолжать следовать стандарту. Не было улучшения относительно пространств имен TS с момента выпуска стандарта модулей ECMAScript в июле 2014 года.
Минусы [модулей ES6]
- Очень утомительно, если каждый класс является другим файлом, вам придется вводить одни и те же операторы импорта снова и снова.
- Переименование файлов нарушит ваш код (плохой).
- Имена классов рефакторинга не будут распространяться на ваш импорт (очень плохо - может зависеть от вашей среды IDE, но я использую vs-code)
Мы можем надеяться на некоторые улучшения по этим вопросам с будущими IDE. Первый из них уже разрешен WebStorm.