Next.js로 Google Cloud Platform에 App Engine 서비스 배포를 진행하고 있습니다. 문제는 production ( 실 서비스 )와 development ( 개발용 )으로 나누어서 .env.development, .env.production의 두개의 환경변수를 가지고있습니다. 배포 시 실서비스 에서는 .env.production을 사용하도록 개발용 에서는 .env.development를 사용하도록 설정하려는데 이것저것 만져보아도 production만 사용하는 문제가 발생해버리네요. 현재 프로젝트구조와 설정코드는 이렇습니다. project ├── local └── Dockerfile └── docker-compose.yml ├── resource └── .next └── ... (Next.js 빌드 파일) └── node_modules └── package.json └── dev_app.yaml └── prd_app.yaml └── .env.development └── .env.production └── next.config.js └── ... (기타 Next.js 프로젝트 파일) 여기서 package.json의 script설정은 다음과 같습니다. { dev: "next dev", start: "next start", lint: "next lint", deploy: "npm run build && gcloud app deploy --project='production' -q --appyaml=prd_app.yaml", deploy:dev: "npm run build:dev && gcloud app deploy --project='development' -q --appyaml=dev_app.yaml", build: "dotenv -e .env.production next build", build:dev: "dotenv -e .env.development next build" } next.config.js는 특별히 건드리지 않았습니다. dev_app.yaml, prd_app.yaml파일은 서비스명만 각각 설정해 주었습니다. runtime: nodejs20 # or another supported version service: development 질문 1. 현재 app engine 업로드된 용량, 로직을 보니 빌드파일이 아닌 프로젝트 그대로 들어가는 것 같습니다. 빌드는 환경변수파일도 정상적으로 분기되는데 앱엔진에서 해당문제가 발생하는 것으로보아 혹시 Next.js에서 빌드된 파일로 app engine에 배포할 수 있는지 궁금합니다. 질문 2. 빌드파일만 올릴수 없다 라고 하더라도 프로젝트 그대로 올리면서 환경변수를 분기할 방법이 있는지 궁금합니다. 정말 문서건 블로그건 구글서칭, 깃허브검색, GPT 모두 끈질기게 시도해봤지만 능력부족 탓인지 성공하지 못했습니다.. 능력자분들께서 도움주시면 잊지않겠습니다!!
[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
class ProductPage extends StatelessWidget { const ProductPage({super.key}); @override Widget build(BuildContext context) { return PaginationListView<ProductModel>( provider: productProvider, itemBuilder: <ProductModel>(_, index, ProductModel model) => GestureDetector( onTap: () => context.goNamed( RestaurantDetailPage.routeName, pathParameters: { 'rid': model.restaurant.id, }, ), child: ProductCard.fromProductModel( model: model, ), ), ); } } 여기서 이상한 에러가 뜹니다. 먼저 'rid': model.restaurant.id 이 부분에서는 아래와 같은 에러가 뜹니다. The property 'restaurant' can't be unconditionally accessed because the receiver can be 'null'. Try making the access conditional (using '?.') or adding a null check to the target ('!').dart unchecked_use_of_nullable_value 그리고 두 번째로, ProductCard.fromProductModel(model: model) 에서는 이런 에러가 뜹니다. The argument type 'ProductModel' can't be assigned to the parameter type 'ProductModel'.dart argument_type_not_assignable 두 에러 모두 이해되지 않습니다. ProductModel 타입을 ProductModel 타입으로 Assign할 수 없다니요? 같은 타입인데 이런 에러가 뜹니다. 또한 첫 번째 에러의 경우에도, 분명히 nullable 타입이 존재하지 않는데 nullable 체크를 하라고 하고 있습니다. 당황스럽습니다. 한편, 강의는 이런 식으로 되어 있습니다. itemBuilder: <ProductModel>(_, index, model) 즉 model 의 타입을 따로 지정해주지 않았습니다. 이렇게 했을경우 model의 타입은 dynamic 이 되며, 자동 완성 기능은 수행할 수 없지만, 결론적으로 잘 작동은 합니다. 그런데 왜 저런 이상한 에러가 발생하는 지 모르겠습니다. 여기 이와 관련된 코드를 덧붙입니다. 그러나 대부분 강의와 동일합니다. @JsonSerializable() class ProductModel implements IModelWithId { @override final String id; /// 상품 이름 final String name; /// 상품 상세 정보 final String detail; /// 상품 이미지 URL @JsonKey(fromJson: DataUtils.pathToUrl) final String imgUrl; /// 상품 가격 final int price; /// 레스토랑 정보 final RestaurantModel restaurant; ProductModel({ required this.id, required this.name, required this.detail, required this.imgUrl, required this.price, required this.restaurant, }); factory ProductModel.fromJson(Map<String, dynamic> json) => _$ProductModelFromJson(json); } typedef PaginationWidgetBuilder<T extends IModelWithId> = Widget Function( BuildContext context, int index, T model, ); 문제가 발생하고 있는 스크린샷:
[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
Token 발급 과정에서 username:password 값을 base64 로 인코딩 후 authorization 헤더에 Basic $token 형태로 전송하는 것이 정석이라고 말씀해주셨습니다. 질문1. Basic $token 형태는 인증정보가 그대로 base64 형태로 인코딩해줍니다. 그러면 누군가가 이 패킷을 까보기만 하면 데이터를 알 수 있는 것이 아닌가요..? 이 부분이 이해가 잘 안되네요. 설명부탁드립니다.. 질문2. 추가로 챗gpt 에게 질문했을 때, 로그인할 때 content type 을 application/x-www-form-urlencoded 형태로 보내라고 하는데, 대부분은 json 형태로 전송하더라구요.. 설명부탁드립니다...
[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
안녕하세요. 영상통화 강의를 끝마치고, 실제 기기 2개(안드로이드, 아이폰)에 같은 코드를 설치해서 실행하면 서로 영상통화가 될 줄 알았는데, 각자 상대방 없음으로 뜨면서, 서로 같은 채널에 입장이 안 되었습니다. Agora SDK 설명서에는 채널이름만 같으면 될 것처럼 써 있었는데 제가 잘못 이해한 것인지... 선생님 설명대로 서버에서 각 기기마다 토큰을 부여 받아야 하므로 기기마다 같은 APP ID에 임시 토큰을 서로 달리 받아야 하는 것인지... 실기기 2개로 영상통화 성공하는 것까지 마무리하고 싶습니다. 선생님께서 힌트를 살짝 주시면 감사하겠습니다.
[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
강의 3번째 보면서 진행중인데 에러 해결이 안되서 문의올립니다. 강의는 섹션 5-5 레스토랑 상세요청 구현하기 입니다. The relevant error-causing widget was: FutureBuilder<Map<String, dynamic>> FutureBuilder:file:///D:/flutter_project/baemin/lib/restaurant/view/restaurant_detail_screen.dart:39:16 39번 라인은 아래 그림보시면 되겠습니다. - 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 코드팩토리 디스코드 https://bit.ly/3HzRzUM Flutter 강의를 구매하시면 코드팩토리 디스코드 서버 플러터 프리미엄 채널에 들어오실 수 있습니다! 디스코드 서버에 들어오시고 저에게 메세지로 강의를 구매하신 이메일을 보내주시면 프리미엄 채널에 등록해드려요! 프리미엄 채널에 들어오시면 모든 질의응답 최우선으로 답변해드립니다!
섹션 1, 14번 강의를 듣던중 궁금한점이 생겨 질문드립니다. 강의에서는 presentation/home/components 구조로 폴더를 작성하셨는데, 만약 home_screen.dart 파일에서 바텀 네비게이션을 제공하고, 바텀네이게이션에는 마이페이지, 홈페이지, 검색페이지 등등 과 같은 홈페이지와 그 성격이 전혀 다른 페이지로 이동할수 있는 버튼들이 존재하는 경우라면 home/components 폴더에 마이페이지, 홈페이지 등 파일 혹은 폴더를 집어넣는다. home 폴더에 다 집어넣는것이 아니라 presentation 폴더에 my_page, search_page 등 폴더를 만들고 각 폴더에 맞는 성격의 파일 및 컴포넌트를 관리한다. 어느것이 바람직 할까요? 그리고 retrofit, json_serializable을 사용할때 저희가 작성하는 dart 파일과 generator가 생성하는 g.dart 파일은 각각 도메인 레이어, 데이터 레이어라고 보면 맞는건가요?
맥북에 Error running pod install 문제를 해결하기 위해서 cd ios && arch -x86_64 pod install && cd .. 강의 자료에 나와 있는 대로 위 코드를 터미널에 입력했는데, cd: no such file or directory: ios 해당 오류 메세지가 나오면서 실행이 되지 않습니다...
[Bloc 응용] 실전 앱 만들기 (책 리뷰 앱) : SNS 로그인, Firebase 적용, Bloc 상태 관리, GoRouter
선생님 실무에서 받는 JSON 데이터가 가끔은 필요한 포맷으로 딱 떨어지지 않을때가 있는데 이럴때 실무에서는 어떻게 해결을 하시나요? 이번에 북 리뷰에도 어떤 책들의 저자들은(길거나, 영문일때 등) ^ 이런 표시가 있어서 사용 환경을 약간 저해하는 듯 싶어서 해결을 하고 싶은데 어떻게 해야할지 감을 못잡겠네요 ㅠ
[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
class _Test extends StatelessWidget { const _Test({super.key}); @override Widget build(BuildContext context) { return const Placeholder(); } } stateless를 탭으로 눌러서 자동 생성했을 때 super.key 부분이 이렇게 생성이 되는데 이건 축약표현인가요? 이경우, final VoidCallback onPressed; const _Test({required this.onPressed, key}); 위 코드를 작성해도 되는 것인지 아니면 강의처럼 아래코드로 작성해야하는지 궁금합니다! final VoidCallback onPressed; const _Test({required this.onPressed, Key? key}) : super(key: key);
[Bloc 응용] 실전 앱 만들기 (책 리뷰 앱) : SNS 로그인, Firebase 적용, Bloc 상태 관리, GoRouter
최근 작성 리뷰 Top10 기능 구현강의 에서 타이틀이랑 작가부분을 퍼블리싱 했는데 오버플로우 오류가 뜨네요 ㅠㅠ 왜 생기는 거고 어떻게 해결을 해야 하나요? 혹시 선생님의 시뮬레이션 기기가 아이폰 pro max 여서 안생겼고, 저는 아이폰 14여서 생기는 건가요? 그러면 유저들이 다양한 디바이스를 쓸텐데 오버플로우 오류를 해결 할 수 있는 방법이 있을까요?ㅠㅠ
[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
선생님 제 Dio버전이 달라서 그런건지 플러터 문제인지 } on DioError catch (e) { 코드에서 DioError를 사용할 수 없다는 메세지가 뜹니다.// 'DioError' is deprecated and shouldn't be used. Use DioException instead. This will be removed in 6.0.0. Try replacing the use of the deprecated member with the replacement. 라는 메세지가 뜨며 DioException을 사용하라는 것 같은데 강의버전과 동일한 dio버전으로 내린뒤에 펍겟해도 똑같이 DioError와 DioErrorType에 선이 그어져있어 // ignore : deprecated_member_use } on DioError catch (e) { 위의 주석코드를 입력하게 되면 DioError 코드 에러가 사라집니다. 이렇게 사용해도 상관이 없는지 DioException을 사용해야 하는지 궁금합니다.