I am pretty new to typescript and recently tried to build a few react pages using ts, however have had a host of problems trying to get it to get it all working.
I am currently trying to integrate react (using typescript) into an existing asp.net core application and have imported the modules using npm. However trying to load the page I receive an uncaught typeerror:
Uncaught TypeError: Failed to resolve module specifier "react".
Relative references must start with either "/", "./", or "../".
My guess here is that the "node_modules" libs are not being made accessible at runtime and need to somehow be in the wwwroot folder (but I may be wrong). Currently the node_modules folder is at the same directory level as the wwwroot folder.
My tsconfig.json:
{
"compilerOptions": {
"target": "ES6",
"lib": ["ES6", "dom"],
"moduleResolution": "Node",
"outDir": "../wwwroot/js/",
"jsx": "react"
}
}
npm packages:
├── #types/bootstrap#5.0.17
├── #types/jquery#3.5.6
├── #types/node#16.4.3
├── #types/react-dom#17.0.9
├── #types/react#17.0.15
├── commonjs#0.0.1
├── react-dom#17.0.2
├── react#17.0.2
└── typescript#4.3.5
Razor Page:
#page
#using System.Data
#using Microsoft.AspNetCore.Html
#model TestSite.Form
#{
ViewData["Title"] = " Form";
}
<div>
<div id='FormContent'></div>
<script type="module" src="/js/Builder/Form.js"></script>
</div>
Form.tsx:
import * as React from 'react';
import { render } from 'react-dom';
class Form extends React.Component
{
constructor()
{
super();
}
render()
{
return (
<div>
<b>Test</b>
</div>
)
}
}
render(
<Form />,
document.getElementById('FormContent')
);
Any ideas on this one?
Many Thanks in advance! :)
I am trying to load an object file from the template. The template is based on ThreeJs library and I am loading using an object loader, see the code here:
loader.load( '{% static "Simu/test.obj" %}', function ( obj ) {
scene.add( obj );
} );
The object file test.obj is stored in a static sub-folder such as myStatic/Simu/test.obj, this is the tree directory of my app:
.
├── myStatic
│ ├── css
│ ├── img
│ ├── js
│ └── Simu
│ ├── 0
│ ├── constant
│ │ ├── polyMesh
│ │ └── triSurface
│ └── system
├── pde
│ ├── migrations
│ │ └── __pycache__
│ ├── __pycache__
│ └── templates
│ └── pde
├── pdeWeb
│ └── __pycache__
└── static
├── admin
│ ├── css
│ │ └── vendor
│ │ └── select2
│ ├── fonts
│ ├── img
│ │ └── gis
│ └── js
│ ├── admin
│ └── vendor
│ ├── jquery
│ ├── select2
│ │ └── i18n
│ └── xregexp
├── css
├── img
└── js
However, when I run the code it cannot find the file and it gives me this error:
Not Found: /pde/{% static "Simu/test.obj" %}
"GET /pde/%7B%%20static%20%22Simu/test.obj%22%20%%7D HTTP/1.1" 404 2102
It seems it is not going to the static folder at all! it tries to reach a folder named pde, why this is happening?
Thank you very much!
I found the mistake. The loader was not in the html template but in a javascript in the static folder. That was causing the error.
I'm writing an angular1 + angular2 hybrid application which uses webpack as package bundler.
In my code I import a library (#angular/upgrade) in this way
import { UpgradeModule } from '#angular/upgrade/static';
Angular upgrade library is sitting in node_module folder with the following tree structure (simplified):
#angular/upgrade
├── bundles
│ ├── upgrade-static.umd.js
│ ├── upgrade-static.umd.min.js
│ ├── upgrade.umd.js
│ └── upgrade.umd.min.js
├── index.d.ts
├── index.js
├── index.js.map
├── index.metadata.json
├── package.json
├── static
│ └── package.json
├── static.d.ts
├── static.js.map
├── static.metadata.json
└── static.js
The problem is that by default webpack resolve my import statement loading #angular/upgrade/static.js, an ES6 file which, once bundled with the rest of the code generate errors.
What I'd like webpack to do instead is loading #angular/upgrade/static/package.json which contains the right main definition pointing to the umd bundle
{"main": "../bundles/upgrade-static.umd.js"}
Is that achievable?
Thanks,
Gab
Although the module resolution described here:
https://webpack.github.io/docs/resolving.html
should be able to do what I've described above by default, in order to achieve that I had to use the resolve.alias property. Here's the configuration that I've used:
resolve: {
extensions: [ '.js', '.ts', '' ],
modulesDirectories: [ path.resolve( __dirname, 'node_modules' ) ],
alias: {
'#angular/upgrade/static$': '../../node_modules/#angular/upgrade/bundles/upgrade-static.umd.js'
}
},
Does import UpgradeModule from '#angular/upgrade/bundles/upgrade-static.umd.js'; work?
Webpack only follows the main in package.json if package.json is at the root level of the npm module, so in this case you'll have to access the file you want directly.
I am developing a web application using the MEAN framework and gulp for minification of the files. However, the application does not work because there are lots of "is not a function, got undefined" when I inspect the navigator console. When I read the app.min.js file which is generated with gulp, I can't find most of javascripts files (controllers, services and so on).
The folder structure that I am using for the client is the following:
client/
├── app.min.js
├── app.min.js.map
├── controllers
│ ├── auth
│ │ ├── login_controller.js
│ │ └── register_controller.js
│ ├── home
│ │ └── home_controller.js
│ ├── navigation
│ │ └── navigation_controller.js
│ └── profile
│ └── profile_controller.js
├── directives
│ └── navigation.js
├── index.html
├── main.js
├── services
│ ├── authentication.js
│ └── data.js
└── views
├── auth
│ ├── login
│ │ └── login.html
│ └── register
│ └── register.html
├── home
│ └── home.html
├── navigation
│ └── navigation.html
└── profile
└── profile.html
This the the gulp file which I am using:
var gulp = require("gulp");
var concat = require("gulp-concat");
var uglify = require("gulp-uglify");
var watch = require("gulp-watch");
var sourcemaps = require("gulp-sourcemaps");
var ngHtml2Js = require("gulp-ng-html2js");
gulp.task("scripts", function() {
gulp.src([
"./client/**/*.js",
"!./client/app.min.js"
]).pipe(sourcemaps.init())
.pipe(concat("./app.min.js"))
.pipe(uglify({mangle: true}))
.pipe(gulp.dest("client"))
.pipe(sourcemaps.write("./"))
.pipe(gulp.dest("client"));
});
gulp.task("watch", function() {
watch(["./client/**/*.js", "!./client/**/*.test.js", "!./client/app.min.js"], function() {
gulp.start("scripts");
});
});
gulp.task("default", ["scripts", "watch"]);
Thanks in advance.
EDIT:
This is the generated app.min.js file:
!function(){function t(t,e){t.when("/",{templateUrl:"views/home/home.html",controller:"homeCtrl",controllerAs:"vm"}).when("/register",{templateUrl:"views/register/register.html",controller:"registerCtrl",controllerAs:"vm"}).when("/login",{templateUrl:"views/login/login.html",controller:"loginCtrl",controllerAs:"vm"}).when("/profile",{templateUrl:"views/profile/profile.html",controller:"profileCtrl",controllerAs:"vm"}).otherwise({redirectTo:"/"}),e.html5Mode(!0)}function e(t,e,n){t.$on("$routeChangeStart",function(t,o,r){"/profile"!==e.path()||n.isLoggedIn()||e.path("/")})}angular.module("app",["ngRoute"]),angular.module("app").config(["$routeProvider","$locationProvider",t]).run(["$rootScope","$location","authentication",e])}(),function(){function t(){return{restrict:"EA",templateUrl:"/views/navigation/navigation.html",controller:"navigationCtrl as navvm"}}angular.module("app").directive("navigation",t)}(),function(){function t(t,e){var n=function(t){e.localStorage["token"]=t},o=function(){return e.localStorage["token"]},r=function(){var t,n=o();return n?(t=n.split(".")[1],t=e.atob(t),t=JSON.parse(t),t.exp>Date.now()/1e3):!1},i=function(){if(r()){var t=o(),n=t.split(".")[1];return n=e.atob(n),n=JSON.parse(n),{email:n.email,name:n.name}}},l=function(e){return t.post("/api/register",e).success(function(t){n(t.token)})},a=function(e){return t.post("/api/login",e).success(function(t){n(t.token)})},c=function(){e.localStorage.removeItem("token")};return{currentUser:i,saveToken:n,getToken:o,isLoggedIn:r,register:l,login:a,logout:c}}angular.module("app").service("authentication",t),t.$inject=["$http","$window"]}(),function(){function t(t,e){var n=function(){return t.get("/api/profile",{headers:{Authorization:"Bearer "+e.getToken()}})};return{getProfile:n}}angular.module("app").service("appData",t),t.$inject=["$http","authentication"]}(),function(){function t(t,e){var n=this;n.credentials={name:"",email:"",password:""},n.onSubmit=function(){console.log("Submitting registration"),e.register(n.credentials).error(function(t){alert(t)}).then(function(){t.path("profile")})}}angular.module("app").controller("registerCtrl",t),t.$inject=["$location","authentication"]}(),function(){function t(){console.log("Home controller is running")}angular.module("app").controller("homeCtrl",t)}(),function(){function t(t,e){var n=this;n.user={},e.getProfile().success(function(t){n.user=t}).error(function(t){console.log(t)})}angular.module("app").controller("profileCtrl",t),t.$inject=["$location","appData"]}();
//# sourceMappingURL=app.min.js.map
As part of learning angular i’ve decided to create a simple bug tracker app using ng-boilerplate as a starting point as I like their approach to folder structure. I’ve got the auth down and have moved onto the "members area” which lists all the users projects and allows them to create new projects and to eventually add bugs to each project.
I’m having a bit of an analysis paralysis in regards to structuring the code the “angular way”. So far I have :
- member
— add-project
—— add.js
—— add.tpl.html
- member.tpl.html
- member.js
inside member.js I have a memberctrl which lists the users projects and adds a new project, calling a factory called ProjectsService (also sitting in member.js) to do both. The ProjectsService currently has two methods, query() and add() although obviously this would grow to include update, delete etc.
The add.js in the add-project folder seems a bit redundant at the moment, but i’m worried that the member controller is going to grow (editing projects, adding bugs, editing bugs etc) so what would be an ideal structure going forward? Should I have a separate addProjectCtrl inside add.js solely for adding a project? Should I remove add() from ProjectsService and move it into its own factory in add.js as well?
Code for member.js is as follows
.controller('MemberCtrl', function MemberCtrl($scope, $location,ProjectsService) {
$scope.projects = [];
$scope.refresh = function () {
ProjectsService.query()
.then(function (data) {
$scope.projects = data;
});
};
$scope.addProject = function (project) {
ProjectsService.add(project).then(function (data) {
$scope.projects = data;
$location.path("/member");
});
};
//is this just going to get bigger and bigger?
$scope.refresh();
})
.factory('ProjectsService', ['$http', '$q', function ($http, $q) {
return {
query: function () {
var deferred = $q.defer();
$http.get('/api/get-projects')
.success(function (data) {
deferred.resolve(data);
})
.error(function (data) {
deferred.reject(data);
});
return deferred.promise;
},
add: function (project) {
var deferred = $q.defer();
$http.post('/api/create-project', project)
.success(function (data) {
deferred.resolve(data);
})
.error(function (data) {
deferred.reject(data);
});
return deferred.promise;
}
};
}])
and code for add.js
angular.module( 'ngBoilerplate.member.add-project', [
'ui.router',
'placeholders',
'ui.bootstrap',
'ngBoilerplate.config',
'ngBoilerplate.member'
])
.config(function config( $stateProvider,USER_ROLES ) {
$stateProvider.state( 'member.add-project', {
url: '/add-project',
views: {
"main": {
templateUrl: 'member/add-project/add.tpl.html'
}
},
data:{ pageTitle: 'Add Project'
}
});
})
;
Take a look at the official angular-seed project, or Yeoman angular generator which will give you a barebone structure for start your angular projects.
A generally good practice is to split into different files your Controllers / Services / Directives.
For a more detailed code guide, read the popular angular-style-guide.
Extracted from it, here is an example of structure :
.
├── app
│ ├── app.js
│ ├── controllers
│ │ ├── home
│ │ │ ├── FirstCtrl.js
│ │ │ └── SecondCtrl.js
│ │ └── about
│ │ └── ThirdCtrl.js
│ ├── directives
│ │ ├── home
│ │ │ └── directive1.js
│ │ └── about
│ │ ├── directive2.js
│ │ └── directive3.js
│ ├── filters
│ │ ├── home
│ │ └── about
│ └── services
│ ├── CommonService.js
│ ├── cache
│ │ ├── Cache1.js
│ │ └── Cache2.js
│ └── models
│ ├── Model1.js
│ └── Model2.js
├── partials
├── lib
└── test