问题
I am currently working on an Electron app using TypeScript and Angular2, for which I have created many different classes, all in separate files. In order to make the refactoring of my app easier, I would like to not have to use the relative path when importing those classes.
Right now, to import them, I use this syntax: import {Trigger} from './../../trigger/ts/trigger.component';
What I would like to do is use a syntax that looks like this: import {Trigger} from 'trigger.component';
Is that possible?
回答1:
You can create one file, for example: components.ts and in that component reference to all components, like:
export {Trigger} from '../trigger/ts/trigger.component'
export {Cmp} from '../cmp/ts/cmp.component'
...
Than, when you want to load one component, you can do:
import {Trigger} from '../components.ts'
It is good practice for grouping things.
回答2:
I created an exporter using ScriptCS to do just that. I wrote it in C#, but you're welcome to re-write it in whatever language you prefer.
Here is an example on GitHub
It allows you to have an export file in the root of each component directory which you can import by doing:
import {LoginPage, HomePage} from '../pages/export'
or
import {NavBarComponent, HeroCardComponent} from '../controls/export'
Say you have multiple components in a specific directory such as:
- app/pages/login-page/login-page.ts
- app/pages/home-page/home-page.ts
- app/controls/nav-bar.ts
- app/controls/hero-card.ts
if you run scriptcs exporter.cs -- app/pages app/controls
It will generate an output file called export.ts
in each of the specified directories with an export statement for each of the classes contained in the directories (which are iterated through recursively)
exporter.cs
// USAGE
// scriptcs exporter.cs -- app/Templates app/Controls
using System.Text.RegularExpressions;
CreateExports();
public void CreateExports() {
// e.g. 'C:\Apps\MyProject'
string rootDir = new DirectoryInfo(@".\").FullName;
string exportFileName = "export.ts";
List<string> exportDirectoryPaths = new List<string>();
foreach (string argument in Env.ScriptArgs) {
if (argument.Contains(".ts"))
exportFileName = argument;
else
exportDirectoryPaths.Add(argument);
}
Console.WriteLine("File Name:" + exportFileName);
foreach (string exportDirPath in exportDirectoryPaths) {
// e.g. 'app\Templates'
var exportDirPathFixed = exportDirPath.Replace("/", "\\");
Console.WriteLine(String.Format("Exporting -> {0}", exportDirPath));
List<ExportEntry> exportEntriesToWrite = new List<ExportEntry>();
// e.g. 'C:\Apps\MyProject\app\Templates'
DirectoryInfo exportDir = new DirectoryInfo(rootDir + exportDirPathFixed);
foreach (FileInfo file in exportDir.EnumerateFiles("*.ts", SearchOption.AllDirectories)) {
// Don't export the export file ;)
if (file.Name == exportFileName)
continue;
// e.g. toAdd = {
// RelativepathToExportDirectory = './app/templates/template-one.component'
// ClassName = 'TemplateOneComponent' (Parsed from file contents, works with interfaces)
ExportEntry toAdd = CreateExportEntry(file, exportDirPathFixed, rootDir);
exportEntriesToWrite.Add(toAdd);
}
CreateExportFile(exportDir.FullName + "\\" + exportFileName, exportEntriesToWrite);
}
}
private void CreateExportFile(string exportFilePath, IEnumerable<ExportEntry> exportEntries) {
string textToWrite = "";
foreach (ExportEntry entry in exportEntries) {
textToWrite += entry.ToString() + Environment.NewLine;
}
Console.WriteLine("Text: " + Environment.NewLine + textToWrite);
File.WriteAllText(exportFilePath, textToWrite);
}
// -- Create Export Entry -- //
private ExportEntry CreateExportEntry(FileInfo exportFile, string exportDirPath, string rootDir) {
ExportEntry toReturn = new ExportEntry() {
ClassName = GetFirstExportClassName(exportFile),
RelativepathToExportDirectory = exportFile.FullName.Remove(0, rootDir.Length + exportDirPath.Length).Replace(".ts", ""),
};
return toReturn;
}
private string GetFirstExportClassName(FileInfo exportFile) {
string className = null;
Regex regular = new Regex(@"(?<=export[\s+]class|interface)[^s+][^\s]+");
using (StreamReader streamer = new StreamReader(exportFile.OpenRead())) {
string contents = streamer.ReadToEnd();
Match componentNameMatch = regular.Match(contents);
className = componentNameMatch.ToString().Replace("{", "");
}
return className;
}
public class ExportEntry {
public string RelativepathToExportDirectory { get; set; }
private string _ClassName;
public string ClassName {
get { return _ClassName; }
set { _ClassName = value.Trim(); }
}
/// <summary>
/// Returns the formatted export entry
/// e.g. " export {MyComponents} from './Components/my-component.component' "
/// </summary>
/// <returns></returns>
public override string ToString() {
// export { AppComponent} from './my-template/my-template.component'
return String.Format("export {{ {0} }} from '.{1}';", this.ClassName, this.RelativepathToExportDirectory).Replace('\\', '/');
}
}
回答3:
Better to use below configuration in tsconfig.json
{
"compilerOptions": {
"...": "reduced for brevity",
"baseUrl": "src",
"paths": {
"@app/*": ["app/*"],
"@trigger/*": ["app/trigger/ts/*"]
}
}
}
For your case, use can do either import {Trigger} from '@app/trigger/ts/trigger.component';
or import {Trigger} from '@trigger/trigger.component';
or any level of path you can configure.
回答4:
A simple way of achieving this is by using the paths of Typescript v2.*, like it is used here: https://github.com/MarkPieszak/aspnetcore-angular2-universal
In summary, you can add a index.ts file to a folder, like
export * from './app.component'
export * from './shared/other.component'
and then have webpack to take care of it. You should add to your webpack.config.js
const clone = require('js.clone');
const ContextReplacementPlugin = require('webpack/lib/ContextReplacementPlugin');
const TsConfigPathsPlugin = require('awesome-typescript-loader').TsConfigPathsPlugin;
[...]
const config = setTypeScriptAlias(require('./tsconfig.json'), {
[...]
plugins: [
new ContextReplacementPlugin(
// The (\\|\/) piece accounts for path separators in *nix and Windows
/angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/,
root('./ClientApp')
),
new TsConfigPathsPlugin({
tsconfig: 'tsconfig.json'
}), [...]
with these help functions:
function setTypeScriptAlias(tsConfig, config) {
var newConfig = clone(config);
newConfig = newConfig || {};
newConfig.resolve = newConfig.resolve || {};
newConfig.resolve.alias = newConfig.resolve.alias || {};
var tsPaths = tsConfig.compilerOptions.paths;
for (var prop in tsPaths) {
newConfig.resolve.alias[prop] = root(tsPaths[prop][0]);
}
return newConfig;
}
function root(args) {
args = Array.prototype.slice.call(arguments, 0);
return path.join.apply(path, [__dirname].concat(args));
}
And finally define the paths in your tsconfig.js
"compilerOptions": {
[...]
"paths": {
"app": [ "./ClientApp/app" ]
},[...]
Then you can just import by the "app" path like
import { AppModule } from 'app';
来源:https://stackoverflow.com/questions/35068813/typescript-how-to-not-use-relative-paths-to-import-classes