Модули и пространства имен: Как правильно организовать большой проект машинописного текста?
Я довольно новичок в машинописи и пишу небольшой фреймворк для создания прототипов для WebGl. В настоящее время я занимаюсь рефакторингом своего проекта и столкнулся с некоторыми проблемами, связанными с организацией своего проекта, поскольку оба подхода (модули и пространства имен), похоже, имеют серьезные недостатки.
Этот пост не о том, КАК использовать эти шаблоны, а о том, как преодолеть проблемы, которые приносит каждый из них.
Status Quo: использование пространств имен
Исходя из C# это казалось самым естественным путем. Каждый класс / модуль получает свое соответствующее пространство имен, и я предоставляю параметр "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
- Прост в использовании, если вы переходите с C#/Java
- Независимо от имен файлов - переименование файлов не нарушит ваш код.
- Простота рефакторинга: IDE могут легко переименовывать пространства имен / классы, и изменения будут применяться последовательно во всем коде.
- Удобство: добавить класс в проект так же просто, как добавить файл и объявить его в нужном пространстве имен.
Cons
Для большинства проектов мы рекомендуем использовать внешние модули и использовать пространство имен для быстрых демонстраций и переноса старого кода JavaScript.
из https://basarat.gitbooks.io/typescript/content/docs/project/namespaces.html
- Корневое пространство имен всегда (?) Глобальный объект (плохо)
- Нельзя (?) Использовать с такими инструментами, как browserify или webpack, которые необходимы для связывания библиотеки с ее зависимостями или связывания вашего пользовательского кода с библиотекой при ее фактическом использовании.
- Плохая практика, если вы планируете выпустить модуль npm
Состояние дел (?): Модули
Typescript поддерживает модули ES6, они являются новыми и блестящими, и все, кажется, согласны с тем, что они - путь. Похоже, идея заключается в том, что каждый файл является модулем, и, добавляя файлы в операторы импорта, вы можете очень четко определить свои зависимости, что упрощает объединение инструментов для эффективной упаковки вашего кода. В основном у меня есть один класс на файл, который, кажется, не очень хорошо работает с шаблоном модуля dhte.
Это моя файловая структура после рефакторинга:
Также у меня есть файл 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, которые также могут объединять все ваши зависимости
- Вы более гибки при импорте классов и вам больше не нужно обходить цепочки пространств имен.
Cons
- Очень утомительно, если каждый класс представляет собой отдельный файл, вам придется вводить одни и те же операторы импорта снова и снова.
- Переименование файлов нарушит ваш код (плохо).
- Рефакторинг имен классов не будет распространяться на ваш импорт (очень плохо - может зависеть от вашей IDE, хотя я использую vs-code)
ИМО оба подхода кажутся ошибочными. Пространства имен кажутся ужасно устаревшими, непрактичными для больших проектов и несовместимыми с обычными инструментами, в то время как использование модулей довольно неудобно и нарушает некоторые функции, для которых я вначале адаптировал машинопись.
В идеальном мире я написал бы свой фреймворк, используя шаблон пространства имен, и экспортировал бы его как модуль, который затем можно было бы импортировать и связать с его зависимостями. Однако это не представляется возможным без некоторых уродливых хаков.
Итак, вот мой вопрос: как вы справились с этими проблемами? Как я могу минимизировать недостатки каждого подхода?
Обновить
Получив немного больше опыта в разработке машинописи и JavaScript в целом, я должен отметить, что модули, вероятно, являются подходящим вариантом для 90% всех вариантов использования.
Надеемся, что последние 10% - это унаследованные проекты, использующие глобальные пространства имен, которые вы хотите оживить небольшим количеством машинописного текста (который, кстати, прекрасно работает).
Большая часть моей критики в отношении модулей может быть (и была) решена лучшей поддержкой IDE. Visual Studio Code с тех пор добавил автоматическое разрешение модуля, которое прекрасно работает.
1 ответ
tl;dr: не выбирай прошлое. Выберите будущее: Модули.
В ранних проектах спецификации модулей ES6 существовало понятие встроенных модулей, которое затем было исключено в сентябре 2013 года. Однако это понятие было уже реализовано командой TypeScript в 2012 году с первыми бета-версиями языка: это были внутренние модули. Затем окончательная спецификация для модулей ES6 была выпущена в июле 2014 года без встроенных модулей. Год спустя, в июле 2015 года, в версии 1.5 TypeScript внутренние модули были переименованы в пространства имен, чтобы избежать путаницы со стандартом.
Пространства имен являются устаревшей функцией. Он не будет частью языка ECMAScript. И команда TypeScript продолжит следовать стандарту. С момента выпуска стандарта модулей ECMAScript в июле 2014 года не произошло никаких улучшений в отношении пространств имен TS.
Минусы [из модулей ES6]
- Очень утомительно, если каждый класс представляет собой отдельный файл, вам придется вводить одни и те же операторы импорта снова и снова.
- Переименование файлов нарушит ваш код (плохо).
- Рефакторинг имен классов не будет распространяться на ваш импорт (очень плохо - может зависеть от вашей IDE, хотя я использую vs-code)
Мы можем надеяться на некоторые улучшения по этим вопросам в будущих IDE. Первый уже решен с помощью WebStorm.