下面,Angular相关代码来自Joost' g代码。我认为Joost使用了Activator。当我使用IntelliJ时,我不得不做出一些改变。总之,我的Angular2应用程序并不适用于IntelliJ和Play框架2.6.x。
步骤:
我从Play网站(2.6.x版)下载了Scala启动项目
我解压缩了zip并执行了sbt run
C:\...\play-scala-starter-example>sbt run
我验证了应用程序在localhost:9000上运行正常。
然后我在IntelliJ中导入了项目。我收到了Info: SBT compilation for play framework 2.x disabled by default
的消息。 问题1 - 我不明白它的含义。
我在IntelliJ中构建并运行项目以检查项目是否仍在运行正常(选择编辑配置选项作为Play 2应用程序)。它是。
我在assets
文件夹中添加了一个app
文件夹,其中包含以下Angular2相关文件(大多数文件来自joost-de-vries项目。我对它们进行了一些修改以编译代码)。
1)assets \ app文件夹,其中包含3个文件 - app.component.ts,app.module.ts,main.ts
app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'my-root',
template: `
<h1>{{title}}</h1>
`
})
export class AppComponent {
title = 'Tour of Heroes';
}
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
imports: [
BrowserModule,
],
declarations: [
AppComponent,
],
bootstrap: [AppComponent]
})
export class AppModule { }
main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);
2)assets \ systemjs.config.js文件
/**
* System configuration for Angular samples
* Adjust as necessary for your application needs.
*/
(function (global) {
System.config({
paths: {
// paths serve as alias
'npm:': 'assets/lib/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
'app': 'assets/app',
// angular bundles
'@angular/core': 'npm:angular__core/bundles/core.umd.js',
'@angular/common': 'npm:angular__common/bundles/common.umd.js',
'@angular/compiler': 'npm:angular__compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:angular__platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:angular__platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:angular__http/bundles/http.umd.js',
'@angular/router': 'npm:angular__router/bundles/router.umd.js',
'@angular/forms': 'npm:angular__forms/bundles/forms.umd.js',
// other libraries
'rxjs': 'npm:rxjs',
'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
defaultExtension: 'js',
meta: {
'./*.js': {
loader: 'assets/systemjs-angular-loader.js'
}
}
},
rxjs: {
defaultExtension: 'js'
}
}
});
})(this);
3)assets \ systemjs-angular-loader.js文件
var templateUrlRegex = /templateUrl\s*:(\s*['"`](.*?)['"`]\s*)/gm;
var stylesRegex = /styleUrls *:(\s*\[[^\]]*?\])/g;
var stringRegex = /(['`"])((?:[^\\]\\\1|.)*?)\1/g;
module.exports.translate = function(load){
if (load.source.indexOf('moduleId') != -1) return load;
var url = document.createElement('a');
url.href = load.address;
var basePathParts = url.pathname.split('/');
basePathParts.pop();
var basePath = basePathParts.join('/');
var baseHref = document.createElement('a');
baseHref.href = this.baseURL;
baseHref = baseHref.pathname;
if (!baseHref.startsWith('/base/')) { // it is not karma
basePath = basePath.replace(baseHref, '');
}
load.source = load.source
.replace(templateUrlRegex, function(match, quote, url){
var resolvedUrl = url;
if (url.startsWith('.')) {
resolvedUrl = basePath + url.substr(1);
}
return 'templateUrl: "' + resolvedUrl + '"';
})
.replace(stylesRegex, function(match, relativeUrls) {
var urls = [];
while ((match = stringRegex.exec(relativeUrls)) !== null) {
if (match[2].startsWith('.')) {
urls.push('"' + basePath + match[2].substr(1) + '"');
} else {
urls.push('"' + match[2] + '"');
}
}
return "styleUrls: [" + urls.join(', ') + "]";
});
return load;
};
将build.sbt更改为以下(再次归功于Joost)
name := """play-scala-starter-example"""
version := "0.2.2"
lazy val root = (project in file(".")).enablePlugins(PlayScala)
scalaVersion := "2.11.11"
incOptions := incOptions.value.withNameHashing(true)
updateOptions := updateOptions.value.withCachedResolution(cachedResoluton = true)
//we use nodejs to make our typescript build as fast as possible
JsEngineKeys.engineType := JsEngineKeys.EngineType.Node
resolvers ++= Seq(
Resolver.jcenterRepo,
Resolver.bintrayRepo("webjars","maven")
)
libraryDependencies ++= {
val ngVersion="4.2.5"
Seq(
guice,
ehcache,
"com.typesafe.play" %% "play-json" % "2.6.1",
//angular2 dependencies
"org.webjars.npm" % "angular__common" % ngVersion,
"org.webjars.npm" % "angular__compiler" % ngVersion,
"org.webjars.npm" % "angular__core" % ngVersion,
"org.webjars.npm" % "angular__http" % ngVersion,
"org.webjars.npm" % "angular__forms" % ngVersion,
"org.webjars.npm" % "angular__router" % ngVersion,
"org.webjars.npm" % "angular__platform-browser-dynamic" % ngVersion,
"org.webjars.npm" % "angular__platform-browser" % ngVersion,
"org.webjars.npm" % "systemjs" % "0.20.14",
"org.webjars.npm" % "rxjs" % "5.4.2",
"org.webjars.npm" % "reflect-metadata" % "0.1.8",
"org.webjars.npm" % "zone.js" % "0.8.4",
"org.webjars.npm" % "core-js" % "2.4.1",
"org.webjars.npm" % "symbol-observable" % "1.0.1",
"org.webjars.npm" % "typescript" % "2.4.1",
//tslint dependency
"org.webjars.npm" % "tslint-eslint-rules" % "3.4.0",
"org.webjars.npm" % "tslint-microsoft-contrib" % "4.0.0"
//"org.webjars.npm" % "codelyzer" % "3.1.1"
//"org.webjars.npm" % "types__jasmine" % "2.5.53" % "test"
//test
//"org.webjars.npm" % "jasmine-core" % "2.6.4"
)
}
dependencyOverrides += "org.webjars.npm" % "minimatch" % "3.0.0"
// use the webjars npm directory (target/web/node_modules ) for resolution of module imports of angular2/core etc
//resolveFromWebjarsNodeModulesDir := true
// compile our tests as commonjs instead of systemjs modules
//(projectTestFile in typescript) := Some("tsconfig.test.json")
// use the combined tslint and eslint rules plus ng2 lint rules
//(rulesDirectories in tslint) := Some(List(
// tslintEslintRulesDir.value,
// ng2LintRulesDir.value
//))
// the naming conventions of our test files
//jasmineFilter in jasmine := GlobFilter("*Test.js") | GlobFilter("*Spec.js") | GlobFilter("*.spec.js")
//logLevel in jasmine := Level.Info
//logLevel in tslint := Level.Info
添加了tsconfig.json
{
/* the configuration of the typescript compiler. See docs https://github.com/Microsoft/TypeScript/wiki/Compiler-Options
The settings outDir and rootDir are managed by sbt-typescript.
*/
"compilerOptions": {
"target": "es5",
"module": "system",
"moduleResolution": "node",
/* the following two settings are required for angular2 annotations to work*/
"emitDecoratorMetadata": true,
"experimentalDecorators":true,
/* for reading your ts source while debugging from a browser */
"sourceMap": true,
"mapRoot": "/assets",
"sourceRoot": "/assets",
"rootDirs": ["app/assets","test/assets"],
"baseUrl": ".",
"paths": {
"*": [
"*",
"target/web/node-modules/main/webjars/*",
"target/web/node-modules/test/webjars/*"
]
},
/* noImplicitAny when you want your typescript to be fully typed */
"strict":true,
"strictNullChecks":false, //doesn't work yet with @angular RC4
"outDir": "./target/ts",
"lib": ["es6", "dom"],
"typeRoots": ["target/web/node-modules/main/webjars/@types","target/web/node-modules/test/webjars/@types"]
}
/* the information below is not used by sbt-typescript. but you can use it if you want to run tsc -p .*/
}
添加了tslint.json
{
"lintOptions": {
"fix": true
},
"rules": {
"no-console": false,
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"eofline": true,
"forin": true,
"import-blacklist": [true, "rxjs"],
"import-spacing": true,
"indent": [
true,
"spaces"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
"static-before-instance",
"variables-before-functions"
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-variable": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [true, "ignore-params"],
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"typeof-compare": true,
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
// "directive-selector": [true, "attribute", "my", "camelCase"],
// "component-selector": [true, "element", "my", "kebab-case"],
// "use-input-property-decorator": true,
// "use-output-property-decorator": true,
// "use-host-property-decorator": true,
// "no-input-rename": true,
// "no-output-rename": true,
// "use-life-cycle-interface": true,
// "use-pipe-transform-interface": true,
// "component-class-suffix": true,
// "directive-class-suffix": true,
// "no-access-missing-member": true,
// "templates-use-public": true,
// "invoke-injectable": true,
"no-empty": true
}
}
然后我添加了在编辑配置中编译Typescript的选项(我修改了之前使用过的Play2 App编辑配置)
然后我添加了Application.scala控制器(信用Joost)
package controllers
import play.api._
import play.api.mvc._
class Application extends InjectedController {
def index = Action {
Ok(views.html.index1())
}
}
然后我添加了index1.scala.html
@()
<!doctype html>
<html lang="en" data-framework="angular2">
<head>
<base href="/" />
@* In this version of the application the typescript compilation is done by the play framework.
The browser downloads .js files. *@
<meta charset="utf-8">
<title>Angular Tour of Heroes</title>
<script type='text/javascript' src='@routes.Assets.versioned("lib/core-js/client/shim.min.js")'></script>
<script type='text/javascript' src='@routes.Assets.versioned("lib/zone.js/dist/zone.js")'></script>
<script type='text/javascript' src='@routes.Assets.versioned("lib/systemjs/dist/system.src.js")'></script>
<script type='text/javascript' src='@routes.Assets.versioned("systemjs.config.js")'></script>
<script type='text/javascript' src='@routes.Assets.versioned("assets/app/main.js")'></script>
<!--script>
System.import('assets/app/main.js').catch(function(err){ console.error(err); });
</script-->
</head>
<body>
<my-root>Loading....</my-root>
</body>
</html>
在上面的代码中,我最初尝试使用
<script>
System.import('assets/app/main.js').catch(function(err){ console.error(err); });
</script>
但Chrome浏览器一直在抱怨安全问题。所以我想直接包含main.js,我假设它会由typescript编译器创建。我怀疑我在这里犯了一些错误。
最后修改了路线文件
GET / controllers.Application.index
该应用程序无法运行。我看到Loading ....
。浏览器控制台上的错误是它无法找到http://localhost:9000/assets/assets/app/main.js
。
我可以看到.js文件是在target \ ts \ app \ assets \ app文件夹中创建的。 问题2 - 我做错了什么?