많이 늦었지만 

좋은 글이 있어 올려봅니다.



개발자가 필히 알아야 할 ES6 10가지 기능



행복한 고수되셔요.


woojja ))*

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\




'Web > JavaScript' 카테고리의 다른 글

[JavaScript] 개발자가 필히 알아야 할 ES6 10가지 기능  (0) 2019.01.15
[JavaScript] WebPack  (0) 2017.10.09
[JavaScript] SystemJS  (0) 2017.10.08
[JavaScript] Interval, Timeout  (0) 2017.02.11
[JavaScript] Markup Insertion  (0) 2017.02.10
[JavaScript] Pop Up 차단 확인  (0) 2017.01.26
Posted by woojja

댓글을 달아 주세요


ASP.NET Core Web 관련 Application 을 IIS 에 배포하려면 Hosting Bundle 이 필요합니다. 


https://dotnet.microsoft.com/download/thank-you/dotnet-runtime-2.1.6-windows-hosting-bundle-installer



그래야 오류없이 올라옵니다.



행복한 고수되셔요...


woojja ))*

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\







Posted by woojja

댓글을 달아 주세요


근래에 ASP.NET Core 에서 Web Socket 을 구성하느라 맨땅에 헤딩을 심하게 했었습니다. ㅋㅋㅋ

그러다 어젯밤에 CodeProject 이멜을 확인하던 중 다음 글이 올라와있더군요.


잠시 보다가 혹시나 WebSocket 을 구성하시는 분에게 도움이 될 듯하여 우리말로 바꾸어 봤습니다.


원문은 이 곳에서 확인 하실 수 있습니다.

원문과 비교하셔 보시고, 원문을 이해하는데 조금이나마 도움이 되었으면 합니다.



ASP.NET Core 에서 Web Socket 을 관리하기 위한 middleware

Startup.cs 를 깨끗하게 유지하는 WebSocket 관리 Logic 을 구성하는 방법. 

소개


ASP.NET Core SignalR 은 Web Application 의 실시간 관리를 단순화한 유용한 Library 이지만
이 글에서는 WebSocket client 와의 더 나은 유연성과 호환성을 위해 WebSockets 를 사용하려한다.
Microsoft 의 문서에서 훌륭한 WebSocket 예제를 찾았지만 한 Connection 에서 다른 Connection으로  message 를 broadcast 이 가능하도록 connection 을 관리하는 기능이 필요하다.
이 기능은 SignalR 에서는 제공하는 기능이다.
이 Logic 은 정말 복잡할걸로 생각하지만 Startup class 에서 이 복잡함을 제거하고자 한다.

Background

ASP.NET 코어에서 WebSocket 지원에 대한 내용은 이 곳에서 확인.
middleware 에 대한 내용과 작성하는 방법을 파악하기 위해서는 이 글을 확인

Code 사용하기


먼저 프로젝트에 Microsoft.AspNetCore.WebSockets package 를 추가해야한다.
그럼 이제 WebSockets 를 관리할 Extension Method 와 Class 를 추가할 수 있다.
 Hide   Shrink   Copy Code
public static class WebSocketExtensions
{
public static IApplicationBuilder UseCustomWebSocketManager(this IApplicationBuilder app)
{
return app.UseMiddleware<CustomWebSocketManager>();
}
}

public class CustomWebSocketManager
{
private readonly RequestDelegate _next;

public CustomWebSocketManager(RequestDelegate next)
{
_next = next;
}

public async Task Invoke(HttpContext context, ICustomWebSocketFactory wsFactory, ICustomWebSocketMessageHandler wsmHandler)
{
if (context.Request.Path == "/ws")
{
if (context.WebSockets.IsWebSocketRequest)
{
string username = context.Request.Query["u"];
if (!string.IsNullOrEmpty(username))
{
WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
CustomWebSocket userWebSocket = new CustomWebSocket()
{
WebSocket = webSocket,
Username = username
};
wsFactory.Add(userWebSocket);
await wsmHandler.SendInitialMessages(userWebSocket);
await Listen(context, userWebSocket, wsFactory, wsmHandler);
}
}
else
{
context.Response.StatusCode = 400;
}
}
await _next(context);
}

private async Task Listen(HttpContext context, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory, ICustomWebSocketMessageHandler wsmHandler)
{
WebSocket webSocket = userWebSocket.WebSocket;
var buffer = new byte[1024 * 4];
WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
while (!result.CloseStatus.HasValue)
{
await wsmHandler.HandleMessage(result, buffer, userWebSocket, wsFactory);
buffer = new byte[1024 * 4];
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
}
wsFactory.Remove(userWebSocket.Username);
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}
}
위 코드에서 보면 WebSocket request(요청) 은 항상 Url 에 "/ws" 를 포함하고 있다.
Query string 에 포함된 parameter 로 u 는 username 으로 WebSocket 과 관련된 login user 를 의미한다.
CustomWebSocket 는 WebSocket 과 username 을 포함한 class 다:
Hide   Copy Code
public class CustomWebSocket
{
public WebSocket WebSocket { get; set; }
public string Username { get; set; }
}
custom WebSocket Message class 도 생성한다:
Hide   Copy Code
class CustomWebSocketMessage
{
public string Text { get; set; }
public DateTime MessagDateTime { get; set; }
public string Username { get; set; }
public WSMessageType Type { get; set; }
}
Type 에는 사용할지도 모를  여러 type 들을 열거한다.
Startup class 에 다음처럼 service 들을 등록해야한다:
Hide   Copy Code
services.AddSingleton<ICustomWebSocketFactory, CustomWebSocketFactory>();
services.AddSingleton<ICustomWebSocketMessageHandler, CustomWebSocketMessageHandler>();
CustomWebSocketFactory 는 연결된 WebSocket 들의 목록을 함께 모아 관리한다:
Hide   Shrink   Copy Code
public interface ICustomWebSocketFactory
{
void Add(CustomWebSocket uws);
void Remove(string username);
List<CustomWebSocket> All();
List<CustomWebSocket> Others(CustomWebSocket client);
CustomWebSocket Client(string username);
}

public class CustomWebSocketFactory : ICustomWebSocketFactory
{
List<CustomWebSocket> List;

public CustomWebSocketFactory()
{
List = new List<CustomWebSocket>();
}

public void Add(CustomWebSocket uws)
{
List.Add(uws);
}

//when disconnect
public void Remove(string username)
{
List.Remove(Client(username));
}

public List<CustomWebSocket> All()
{
return List;
}
public List<CustomWebSocket> Others(CustomWebSocket client)
{
return List.Where(c => c.Username != client.Username).ToList();
}
public CustomWebSocket Client(string username)
{
return List.First(c=>c.Username == username);
}
}
CustomWebSocketMessageHandler 는 message 에 관한 Logic 을 포함한다 (예를들어 , 연결시 어떤 메시지를 전송해야하는지, 수신된 message 에 어떻게 처리해야하는지에 대한 Logic이다)
Hide   Shrink   Copy Code
public interface ICustomWebSocketMessageHandler
{
Task SendInitialMessages(CustomWebSocket userWebSocket);
Task HandleMessage(WebSocketReceiveResult result, byte[] buffer, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory);
Task BroadcastOthers(byte[] buffer, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory);
Task BroadcastAll(byte[] buffer, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory);
}

public class CustomWebSocketMessageHandler : ICustomWebSocketMessageHandler
{
public async Task SendInitialMessages(CustomWebSocket userWebSocket)
{
WebSocket webSocket = userWebSocket.WebSocket;
var msg = new CustomWebSocketMessage
{
MessagDateTime = DateTime.Now,
Type = WSMessageType.anyType,
Text = anyText,
Username = "system"
};

string serialisedMessage = JsonConvert.SerializeObject(msg);
byte[] bytes = Encoding.ASCII.GetBytes(serialisedMessage);
await webSocket.SendAsync(new ArraySegment<byte>(bytes, 0, bytes.Length), WebSocketMessageType.Text, true, CancellationToken.None);
}

public async Task HandleMessage(WebSocketReceiveResult result, byte[] buffer, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory)
{
string msg = Encoding.ASCII.GetString(buffer);
try
{
var message = JsonConvert.DeserializeObject<CustomWebSocketMessage>(msg);
if (message.Type == WSMessageType.anyType)
{
await BroadcastOthers(buffer, userWebSocket, wsFactory);
}
}
catch (Exception e)
{
await userWebSocket.WebSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
}
}

public async Task BroadcastOthers(byte[] buffer, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory)
{
var others = wsFactory.Others(userWebSocket);
foreach (var uws in others)
{
await uws.WebSocket.SendAsync(new ArraySegment<byte>(buffer, 0, buffer.Length), WebSocketMessageType.Text, true, CancellationToken.None);
}
}

public async Task BroadcastAll(byte[] buffer, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory)
{
var all = wsFactory.All();
foreach (var uws in all)
{
await uws.WebSocket.SendAsync(new ArraySegment<byte>(buffer, 0, buffer.Length), WebSocketMessageType.Text, true, CancellationToken.None);
}
}
}
마지막으로, Startup class 의 Configure method 에 다음 code 를 추가한다:
Hide   Copy Code
var webSocketOptions = new WebSocketOptions()
{
KeepAliveInterval = TimeSpan.FromSeconds(120),
ReceiveBufferSize = 4 * 1024
};

app.UseWebSockets(webSocketOptions);
app.UseCustomWebSocketManager();
So, in this way the Starup class remains clean and the logics to manage the WebSockets can grows giving you the flexibility to organize it as you prefer.
자. 이 방법을 통해 Starup class 를 깨끗하게 만들었고 WebSocket 를 관리하는 Logic 이 계속 늘어남으로써 Logic 을 관리하는데  여러분이 원하는데로 구성할 수 있는 유연성을 제공한다.



영어가 유창하지 않아 제대로 바뀌어 지지 않았을 것입니다.

제 글을 100% 믿지 마시고 원문도 한번 확인해 보셨으면 합니다. ^^;



행복한 고수되셔요.


woojja ))*

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\






Posted by woojja

댓글을 달아 주세요


[ASP.NET Core] WebAPI 구축하기.


ASP.NET Core WebAPI 를 구축하면서 어려움을 느꼈던 부분을 풀어 보겠습니다.


제가 이야기 하는 내용은 제가 공부하면서 알게된 내용을 정리한 것으로 개념을 잡는데 도움이 되리라 생각합니다.

다른 여러 Article 을 보시게 되면 더 많은 내용을 추가하실수 있을 겁니다.


그럼 Project 를 생성하면서 시작해 보겠습니다.




ASP.NET Core WebApplication Template 을 선택합니다.



나타나는 창에서 API 를 선택하고요. .NET 의 버전은 .NET Core 의 ASP.NET Core 2.1 을 사용하도록 하겠습니다.



OK 를 클릭하면 Project 를 생성합니다.



그럼 초기화면이 나타나지요.



생성된 폴더와 파일들 중에서 Properties 폴더를 열어서 launchSettings.json 을 클릭하여 열어봅니다.

이 파일에는 IIS Express 에 대한 내용이 들어 있습니다.

이 Project 의 경우에는 62148 port 를 사용하겠다고 적혀 있네요.


이번 Service 를 구축하면서 HTTPS 설정이 들어 갈텐데요. 

그 정보에 대한 내용을 이야기 할 때 다시한번 살펴보겠습니다.



이젠 Startup.cs 파일을 살펴보겠습니다.



Startup 클래스는 application 이 실행하면서 필요한 service 와 application 의 request pipeline 을 구성합니다.


이곳에는 Startup class 의 Constructor 와 두개의 중요한 Method 가 있습니다.


두 Method 의 역할은 주석에 간단하게 나타나 있습니다.

ConfigureServices Method 는 Application 에서 사용할 Service 를 Container 에 추가하는 곳입니다.

Configure Method 에서는 HTTP Request pipeline 을 구성합니다.


ASP.NET Core 에서는 기본적으로 Dependency Injection 을 지원합니다.



상단에 보시면 using Microsoft.Extentions.DependencyInjection; 을 보실 수 있는데 이 Namespace 내의 Extention Method 를 통해서 Service 를 등록할 수 있게 합니다.


ConfigurationServices Method 를 보시면 기본적으로 services.AddMvc() 가 추가되어 있는 걸 보실 수 있습니다

이 구문을 통해 Razor Page 와 MVC Request 를 처리할 수 있게 합니다.


Configure Method 에는  HTTP Request pipeline 을 구성한다고 했는데

수신된 Request 를 처리하는 순서대로 Middleware 를 추가합니다.




ConfigurationService Method 에 한가지 Setting 을 하려고 합니다.

ASP.NET Core 의 routing Middleware 는 controller name 을 rendering 할 때 Pascal Case 를 사용하는데요.

URL 에 lowercase 로 rendering 되도록 하려합니다.



주석을 영문, 한글로 다 달아 봤는데요. 

영어가 짧더라도 이해해 주시고요. 많이 어색하면 알려주셔요. 고치도록 하겠습니다. ^^;


그리고 마지막으로 중요한 사항인데요.

ConfigurationServices Method 의 경우 추가되는 Service 의 순서는 중요하지 않지만.

Configure Method 의 경우는 수신된 Request 가 처리되는 Pipeline 을 구성하는 것이므로 순서가 아주 중요하다는 것을 기억하시기 바랍니다.


간단간단하게 구성하며 정리를 하려했는데...

언제나 그렇지만 적어 내려가면서 계속 내용이 늘어나네요...


Series 가 좀 늘어날 수도 있으리라 생각이 들긴합니다. ^^;


다음 글에서는 Controller 를 추가해가면서 Test 를 진행해 보도록 하겠습니다.


Source


행복한 고수되셔요.


woojja ))*

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\








Posted by woojja

댓글을 달아 주세요

저는 EntityFramework 사용하는 걸 별로 안좋아라 하는데요.


이 기능은 괜찮은 듯합니다. ^^;


FromSql 과 ExecuteSqlCommandAsync 입니다.


이 구문을 사용하면 Stored Procedure 를 사용할 수 있는데요.


이 구문을 사용하다가 Error 가 발생했습니다.



아래를 보시면 분명히 Stored Procedure 의 Parameter 가 선언이 되어 있는데요.

선언이 안되어 있다면서... 오류를 뱉내요...

철자가 틀린 것도 아닌데요. ㅡㅡ;



그래서 또 우리의 친구 Google 을 찾아 갔습니다.


그 결과 두둥!!!


EF Core 는 Parameter 이름을 지정하는 기능을 지원하지 않는다고 하네요. 그래서 Parameter 를 순서대로 @p0, @p1, ... 이런식으로 나열을 해야한다고 합니다. 헐렝...




그래서 고쳐서 Test 해 본 결과 

되네요... 



100% 맘에 드는 건 아니네요. ㅡㅡ;


그리고 INSERT, UPDATE, DELETE 를 할 때 ExecuteSqlCommandAsync 를 사용할 수 있는데요.

이 녀석은 적용받은 Row 의 수, int 값 만을 반환합니다. 알아두셔요. 



행복한 고수되셔요.



woojja ))*

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\




Posted by woojja

댓글을 달아 주세요


REST API 의 예제를 보면 여러 Parameter 를 사용하는 Method 를 볼 수있습니다.

간단히? 되리라 생각하지만 턱 하니 막히기도 하지요.


예제를 보면 아래와 같이 Method 에 사용하는 Multiple Parameter 지만 에 일반 Parameter 와 [FromBody] Attribute 를 달고 있는 Parameter 를 한꺼번에 사용하는 녀석을 만날 수 있습니다. 


// PUT api/values/5
        public void Put(int id, [FromBody]string value)
        {
        }

 ASP.NET Core 로 개발 중 위와 같은 Method 를 Postman 에서 테스트하는 중 Value 에 값이 Null 로 들어오는 것을 발견했습니다. 




Postman 에서 Test 시 요로케 입력하면 되는군요... ㅋㅋㅋ



구글링하다 알게 되었네요...




행복한 고수되셔요...


woojja ))*

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\






Posted by woojja

댓글을 달아 주세요


RestAPI 호출시 발생한 ajax Error 0




문제는 CORS 설정때문이었다.


Cors 에 대한 내용을 추가해주자...



Startup.cs


    public class Startup

    {

        public IConfiguration Configuration { get; set; }


        public Startup(IConfiguration configuration)

        {

            Configuration = configuration;

        }


        // This method gets called by the runtime. Use this method to add services to the container.

        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940

        public void ConfigureServices(IServiceCollection services)

        {

            // services.AddMvc(); 보다 앞에 위치 시킨다. (이건 Test 해보지 않았다. ^^;)

            services.AddCors();


            services.AddMvc();


            services.AddDataAccess();

            services.AddBusinessLogics();


            var configBuilder = new ConfigurationBuilder()

               .SetBasePath(Directory.GetCurrentDirectory())

               .AddJsonFile("appsettings.json", optional: true);

            var config = configBuilder.Build();


            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

        }


        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)

        {

            if (env.IsDevelopment())

            {

                app.UseDeveloperExceptionPage();

            }


            // app.UseMvc(); 보다 앞에 위치 시킨다.

            app.UseOptions();


            //app.UseCors(builder => 

            //    builder.AllowAnyOrigin()

            //    .AllowCredentials()

            //    .AllowAnyHeader()

            //    .AllowAnyMethod()

            //    //.WithMethods("POST,GET,PUT,PATCH,DELETE,OPTIONS")

            //);


            //app.UseCors(builder =>


            //    //builder.AllowAnyOrigin().AllowAnyMethod()

            //    //.WithHeaders(HeaderNames.ContentType, "Authorization", "X-Requested-With")

            

//    builder.WithOrigins("*")

            //    //.AllowAnyOrigin()

            //    .AllowCredentials()

            //    .WithMethods("POST,GET,PUT,PATCH,DELETE,OPTIONS")

            //    .AllowAnyHeader()

            //    //.WithHeaders("Authorization", "X-Requested-With")

            //    );


            app.UseMvc();


            app.UseMvcWithDefaultRoute();


        }

    }



OptionsMiddleware.cs

    public static class OptionsMiddlewareExtensions

    {

        public static IApplicationBuilder UseOptions(this IApplicationBuilder builder)

        {

            return builder.UseMiddleware<OptionsMiddleware>();

        }

    }


    public class OptionsMiddleware

    {

        private readonly RequestDelegate _next;

        private IHostingEnvironment _environment;


        public OptionsMiddleware(RequestDelegate next, IHostingEnvironment environment)

        {

            _next = next;

            _environment = environment;

        }


        public async Task Invoke(HttpContext context)

        {

            this.BeginInvoke(context);

            await this._next.Invoke(context);

        }


        private async void BeginInvoke(HttpContext context)

        {

            //context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

            ////context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*", (string)context.Request.Headers["Origin"] });

            ////context.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "Origin, X-Requested-With, Content-Type, Content-Type: application/json, Accept, Accept: application/json, Authorization" });

            //context.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "*" });

            //context.Response.Headers.Add("Access-Control-Allow-Methods", new[] { "GET, POST, PUT, DELETE, OPTIONS" });

            //context.Response.Headers.Add("Access-Control-Allow-Credentials", new[] { "true" });


            context.Response.Headers.Add("Access-Control-Allow-Origin", "*");

            context.Response.Headers.Add("Access-Control-Allow-Credentials", "true");

            // Added "Accept-Encoding" to this list

            //context.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "*" });

            context.Response.Headers.Add("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Requested-With, Accept, Accept-Version, Accept-Encoding, Content-Encoding, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");

            context.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");


            if (context.Request.Method == "OPTIONS")

            {

                //context.Response.StatusCode = 200;

                //await context.Response.WriteAsync("OK");


                context.Response.StatusCode = (int)HttpStatusCode.OK;

                await context.Response.WriteAsync(string.Empty);

            }


        }

    }



Startup.cs 에서 


            .AllowAnyMethod() 대신 


            .WithMethods("POST,GET,PUT,PATCH,DELETE,OPTIONS") 로 변경해 보았는데.



Origin 과는 전혀 상관없는 오류가 발생했다. ㅡㅡ;

그렇다면 모든 Methos 를 열어줘야 한다는 이야기가 되는데... 그럼 안되겠죠? ㅋㅋ


그래서 app.UseCors(....) 를 사용하지 않고 위에 적어 놓은 Middleware 를 사용하기로 결정했다. 

Origins 의 경우는  Test 를 거쳐 변경할 예정이다.

Headers 의 경우도 현재는 Authorization, Content-Type, X-Requested-With 만 필요하지만 일단 다른 Header 들도 추가해 놓은 상태다.



ASP.NET Core 의 경우 ASP.NET 보다 유연하겠구나 라는 생각이 들긴하지만 서비스 내용을 바탕으로 설정해줘야 할 것들을 숙지하고 해둬야 하겠다.


이젠 WebSocket 을 붙여야 하는 상황인데...

Test 를 해보니 Socket 으로 가야할 녀석이 Controller 로 Routing 되는 걸 알게 되었다.


그럼 이만 Socket Test 하러... 슝~!




행복한 고수되셔요.


woojja ))*

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\




Posted by woojja

댓글을 달아 주세요

VisualStudio Code 에서 React 개발환경을 설정하는 순서를 나열해 봤습니다.


Typescript

Webpack

React

을 구성했고 추가적으로 

react-hot-loader

Babel

TSLint


를 설정하는 방법을 기술하였습니다.


추후 화면 Capture 를 추가할 예정입니다. (일단은 제가 확인하기 위한 내용으로...)



<source path>\React\>mkdir typescript-react-webpack

<source path>\React\>cd typescript-react-webpack


<source path>\React\typescript-react-webpack>code .

<source path>\React\typescript-react-webpack>mkdir src

<source path>\React\typescript-react-webpack>mkdir build


npm config list


npm set init.author.name "<Your Name>"

npm set init.author.email "yourAccount@woojja.com"

npm set init.author.url "www.woojja.com"

npm set init.license "MIT"



<source path>\React\typescript-react-webpack>npm init -y


Wrote to 

<source path>\React\typescript-react-webpack\package.json:


######################  package.json  ###########################

{

  "name": "typescript-react-webpack",

  "version": "1.0.0",

  "description": "",

  "main": "index.js",

  "scripts": {

    "test": "echo \"Error: no test specified\" && exit 1"

  },

  "keywords": [],

  "author": "JH.Woo <woojja@bachilab.com> (www.bachilab.com)",

  "license": "MIT"

}

###############################################################



Part 1 — Typescript and Webpack


<source path>\React\typescript-react-webpack>npm install --save-dev typescript webpack webpack-cli


<source path>\React\typescript-react-webpack>copy con webpack.config.js


ctlr + z


######################  webpack.config.js  ###########################


var path = require("path");


var config = {

    mode: 'development',

  /*

   * app.ts represents the entry point to your web application. Webpack will

   * recursively go through every "require" statement in app.ts and

   * efficiently build out the application's dependency tree.

   */

  entry: ["./src/app.ts"],


  /*

   * The combination of path and filename tells Webpack what name to give to

   * the final bundled JavaScript file and where to store this file.

   */

  output: {

    path: path.resolve(__dirname, "build"),

    filename: "bundle.js"

  },


  /*

   * resolve lets Webpack now in advance what file extensions you plan on

   * "require"ing into the web application, and allows you to drop them

   * in your code.

   */

  resolve: {

    extensions: ["*", ".ts", ".tsx", ".js"]

  },


  module: {

    /*

     * Each loader needs an associated Regex test that goes through each

     * of the files you've included (or in this case, all files but the

     * ones in the excluded directories) and finds all files that pass

     * the test. Then it will apply the loader to that file. I haven't

     * installed ts-loader yet, but will do that shortly.

     */

    rules: [

      {

        test: /\.tsx?$/,

        exclude: /node_modules/,

        use: ['ts-loader']

      }

    ]

  }

};


module.exports = config;


###################################################################




<source path>\React\typescript-react-webpack>npm  install --save-dev ts-loader



make file : index.html, src/app.ts, and src/some_module.ts


##########################  src/some_module.ts  ########################

const greeting: string = "Hello World!";


export default greeting;

###################################################################


##########################  src/app.ts  ################################

import greeting from "./some_module";


console.log(greeting);

###################################################################


##########################  index.html ################################

<!DOCTYPE html>

<html>

  <head>

    <meta charset="utf-8">

    <title>Getting Started with Typescript, ReactJS, and Webpack</title>

  </head>

  <body>

    <script src="build/bundle.js"></script>

  </body>

</html>

###################################################################


<source path>\React\typescript-react-webpack2>copy con tsconfig.json

{

    "compilerOptions": {

      "jsx": "react",

      "module": "commonjs",

      "noImplicitAny": true,

      "outDir": "./build/",

      "preserveConstEnums": true,

      "removeComments": true,

      "target": "ES5"

    },

    "exclude": [

      "node_modules"

    ]

}

ctlr + z


<source path>\React\typescript-react-webpack>npm run build


index.html 실행



console 확인.




Part 2 — ReactJS


<source path>\React\typescript-react-webpack>npm install --save react react-dom


<source path>\React\typescript-react-webpack>npm install --save-dev @types/react @types/react-dom @types/react-router-dom // @types/webpack-env


############################## some_module.ts ==>  Hello.tsx #####################################

// Remember to rename your file to Hello.tsx and

// place it within your src/ directory

import * as React from "react";


interface HelloProps {

  name: string;

}


class Hello extends React.Component<HelloProps, {}> {

  render() {

    return <div>Hello, {this.props.name}</div>;

  }

}


export default Hello;

###################################################################



########################### app.ts ==>  app.tsx  ########################################

import * as React from "react";

import * as ReactDOM from "react-dom";

import Hello from "./Hello";


ReactDOM.render(

  <Hello name="Willson" />,

  document.getElementById("root")

);

###################################################################


##########################  index.html ###############################

<!DOCTYPE html>

<html>

  <head>

    <meta charset="utf-8">

    <title>Getting Started with Typescript, ReactJS, and Webpack</title>

  </head>

  <body>

    <!-- this is where our Hello component will get rendered into -->

    <div id="root"></div>


    <script src="build/bundle.js"></script>

  </body>

</html>

###################################################################



########################  webpack.config.js  ############################

var path = require("path");


var config = {

    mode: 'development',

  /*

   * app.ts represents the entry point to your web application. Webpack will

   * recursively go through every "require" statement in app.ts and

   * efficiently build out the application's dependency tree.

   */

  entry: ["./src/app.tsx"],


  /*

   * The combination of path and filename tells Webpack what name to give to

   * the final bundled JavaScript file and where to store this file.

   */

  output: {

    path: path.resolve(__dirname, "build"),

    filename: "bundle.js"

  },


  /*

   * resolve lets Webpack now in advance what file extensions you plan on

   * "require"ing into the web application, and allows you to drop them

   * in your code.

   */

  resolve: {

    extensions: ["*", ".ts", ".tsx", ".js"]

  },


  module: {

    /*

     * Each loader needs an associated Regex test that goes through each

     * of the files you've included (or in this case, all files but the

     * ones in the excluded directories) and finds all files that pass

     * the test. Then it will apply the loader to that file. I haven't

     * installed ts-loader yet, but will do that shortly.

     */

    rules: [

      {

        test: /\.tsx?$/,

        exclude: /node_modules/,

        use: ['ts-loader']

      }

    ]

  }

};


module.exports = config;

####################################################################


<source path>\React\typescript-react-webpack>npm run build



part 3 — Hot Module Replacement in React (react-hot-loader)


npm install --save-dev react-hot-loader


########################  webpack.config.js  #############################

const webpack = require('webpack');


module.exports = {

...,


plugins: [

new webpack.HotModuleReplacementPlugin()

], 

...


}


####################################################################


A huge development boost will give you react-hot-loader (Hot Module Replacement). 

It will shorten your feedback loop during development. 

Basically whenever you change something in your source code, 

the change will apply in your app running in the browser without reloading the entire page.


######################## app.tsx  ##################################

import * as React from "react";

import * as ReactDOM from "react-dom";

import Hello from "./Hello";


ReactDOM.render(

    <Hello name="Willson" />,

    document.getElementById("root")

  );


module.hot.accept();

####################################################################


참고 :

https://medium.com/@francesco.agnoletto/how-to-set-up-typescript-with-babel-and-webpack-6fba1b6e72d5


https://github.com/Kornil/simple-ts-react-app




import * as React from "react";

import * as ReactDOM from "react-dom";

// hot reload for development

import { AppContainer } from "react-hot-loader";


import App from "./App";


import "./style.scss";


const root = document.getElementById("root") as HTMLElement;


const render = (Component: React.SFC) => {

  ReactDOM.render(

    <AppContainer>

      <Component />

    </AppContainer>,

    root,

  );

};


render(App);


if (module.hot) {

  module.hot.accept("./App", () => {

    render(App);

  });

}


module.hot.accept();

####################################################################


Part 4 — Babel



<source path>\React\typescript-react-webpack>npm install --save-dev babel-core babel-loader

<source path>\React\typescript-react-webpack>npm install --save-dev @babel/core source-map-loader

<source path>\React\typescript-react-webpack>npm install --save-dev @babel/preset-typescript @babel/preset-react @babel/preset-env



<source path>\React\typescript-react-webpack>copy con .babelrc

{

  "presets": ["@babel/react", "@babel/typescript", ["@babel/env", { "modules": false }]]

}

ctrl + z



Tokenization is skipped for lines longer than 20k characters for performance reasons.



part 5 — Setting up TSLint


npm install --save-dev tslint tslint-react



########################  tslint.json  ##################################

{

  "extends": ["tslint:recommended", "tslint-react"],

  "rules": {}

}

####################################################################


행복한 고수되십시오. 


woojja ))*

\\\\\\\\\\\\\\\\\\\\\\\\\\




Posted by woojja

댓글을 달아 주세요


안녕하세요? 


WebAPI 을 작성하면서 Autofac 을 사용해 보려는데...

이거 뭐... 현명한 선택인지... ^^;


Owin 이 포함되어야하므로...


Install-Package Autofac

Install-Package Autofac.Owin

Install-Package Autofac.WebApi2

Install-Package Autofac.WebApi2.Owin


행복한 고수되셔요.


woojja ))*

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\




Posted by woojja

댓글을 달아 주세요

2018. 2. 19. 11:20

VisualStudio Code 를 이용하여 React 로 조그만 예제를 만들면서 정리한 내용...


개인적인 정리 내용입니다. 

 


React 를 생성하려면 WebPack이 필요하고 별도의 설정이 필요하지만 대신 

facebook 에서 만든 Create-React-App 을 사용하면 

별도의 WebPack 설치와 설정없이도 React 를 개발 할 수 있다.


npm install -g create-react-app



create-react-app movie-app 은 Terminal 에서 실행하는 것이 좋다.

VS Code 에서 실행 시 Error 가 발생한다.



cd movie-app



vscode terminal 에서 


npm start


port 를 바꾸고 싶을 때는 

"PORT=4000 npm start" 

를 입력한다.


propTypes


propTypes 변수에 담아야 한다.


    static propTypes = {

        title:PropTypes.string.isRequired,

        image:PropTypes.string.isRequired

    }



React Life Cycle


Render : componentWillMount() => render() => componentDidMount()


Update : componentWillReceiveProps() => shouldComponentUpdate() = true => componentWillUpdate() => render() => componentDidUpdate()


State 는 state 배열에 담아야 한다.

state 를 변경할 때는 

      this.setState({greeting : 'woojja'}) 와 같이  setState 를 사용하여 값을 변경


state  를 변경하면 render 가 다시 실행된다.


        movies : [

            {

              id:16,

              title:'transformer',

              poster:'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSsdR9axnghll6mVM3Yae1r7Il0A8yGc_JJynAiH_fCXwSANcRj'

            }, 

            ...this.state.movies // '...' : 기존의 Data 를 유지한다는 의미 

        ]


smart component, dumb component



class component (smart component) : state 를 가짐.

class Movie extends Component{


    render() {

        return(

            ...

        );

    }

}


functional component (dumb component) : state 를 가지지 않는다. Life cycle, render function 도 없고 Props 만 가지며 

단순 Return 만 존재한다.


function MoviePoster({image, title}){

    return(<img src={image} alt={title + ' Poster'} />);

}


functional component 의 Validation Check


MoviePoster.PropTypes = {

    poster : PropTypes.string.isRequired

}


Promise : 새로운 Concept (Asynchronous programming)



=> arrow function 에는 return 의미가 포함되어 있음.



www.npmjs.com/package/react-lines-ellipsis


npm install --save react-lines-ellipsis


import LinesEllipsis from "react-lines-ellipsis"




npm run build


  39.99 KB  build/static/js/main.47ccf7c1.js

  706 B     build/static/css/main.a3112408.css


압축해서 build folder 에 넣음.


Package.json 에 아래 구문을 추가

  "homepage" : "https://github.com/iPeterPan/react_movie_app",


변경했으니 다시한번 

npm run build


Install gh-pages and add deploy to scripts in package.json


npm install --save gh-pages


Package.json 에 아래 구문을 추가

"predeploy": "npm run build",

"deploy": "gh-pages -d build"


특정 branch 를 deploy 하려면

"deploy": "gh-pages -b master -d build",


The predeploy script will run automatically before deploy is run.

If you are deploying to a GitHub user page instead of a project page you'll need to make two additional modifications:


First, change your repository's source branch to be any branch other than master.

Additionally, tweak your package.json scripts to push deployments to master:



Deploy the site by running npm run deploy


npm run deploy


Ensure your project’s settings use gh-pages

Finally, make sure GitHub Pages option in your GitHub project settings is set to use the gh-pages branch:





  "scripts": {

    "start": "react-scripts start",

    "build": "react-scripts build",

    "test": "react-scripts test --env=jsdom",

    "eject": "react-scripts eject",

    "predeploy": "npm run build",

    "deploy": "gh-pages -b master -d build -repo https://github.com/iPeterPan/react_movie_app.git"

  }



행복한 고수되셔요...  ^^


woojja ))*

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\




'Web > React' 카테고리의 다른 글

[React] React 정리  (0) 2018.02.19
Posted by woojja

댓글을 달아 주세요