pas2jsdsgn: progressive web app: auto create serviceworker project

This commit is contained in:
mattias 2022-04-05 23:48:20 +02:00
parent 612e6e1932
commit fc055bd7fb
4 changed files with 174 additions and 107 deletions

View File

@ -2,10 +2,10 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm
Left = 431
Height = 538
Top = 310
Width = 635
Width = 632
Caption = 'Pas2JS Browser project options'
ClientHeight = 538
ClientWidth = 635
ClientWidth = 632
OnCreate = FormCreate
OnShow = FormShow
Position = poScreenCenter
@ -54,7 +54,7 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm
Left = 6
Height = 40
Top = 492
Width = 623
Width = 620
OKButton.Name = 'OKButton'
OKButton.DefaultCaption = True
HelpButton.Name = 'HelpButton'
@ -125,15 +125,16 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm
AnchorSideLeft.Control = RBUseURL
AnchorSideTop.Control = RBUseURL
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = edtWasmProgram
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
Left = 70
Height = 30
Top = 364
Width = 559
Width = 556
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Left = 32
BorderSpacing.Top = 6
BorderSpacing.Right = 6
BorderSpacing.Bottom = 6
ItemHeight = 0
TabOrder = 8
@ -197,7 +198,7 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm
Left = 70
Height = 30
Top = 180
Width = 559
Width = 556
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Left = 32
BorderSpacing.Top = 6

View File

@ -68,7 +68,7 @@ type
function CreateHTMLFile(AProject: TLazProject; aScriptFileName: String
): TLazProjectFile; virtual;
function CreateProjectSource: String; virtual;
Function DoInitDescriptor : TModalResult; override;
Function DoInitDescriptor: TModalResult; override;
function GetNextPort: Word; virtual;
function ShowOptionsDialog: TModalResult; virtual;
function ShowModalOptions(Frm: TWebBrowserProjectOptionsForm): TModalResult; virtual;
@ -92,10 +92,11 @@ type
{ TProjectPas2JSServiceWorker }
TProjectPas2JSServiceWorker = class(TProjectDescriptor)
protected
function CreateProjectSource: String; virtual;
public
constructor Create; override;
function CreateProjectSource: String; virtual;
function InitServiceWorkerProject(AProject: TLazProject;
LPRFilename: string): TModalResult; virtual;
function GetLocalizedName: string; override;
function GetLocalizedDescription: string; override;
function InitProject(AProject: TLazProject): TModalResult; override;
@ -111,6 +112,7 @@ type
FImagesDir: string;
FManifestFilename: string;
FProjectDir: string;
FServiceWorker: TProjectPas2JSServiceWorker;
FServiceWorkerLPR: string;
FWebDir: string;
protected
@ -141,6 +143,7 @@ type
property WebDir: string read FWebDir write FWebDir;
property ManifestFilename: string read FManifestFilename write FManifestFilename;
property IconSizes: TWordDynArray read FIconSizes write FIconSizes;
property ServiceWorker: TProjectPas2JSServiceWorker read FServiceWorker write FServiceWorker;
end;
{ TProjectPas2JSNodeJSApp }
@ -261,6 +264,8 @@ procedure Register;
Var
ViewCategory : TIDECommandCategory;
IDECommand : TIDECommand;
SrvWorker: TProjectPas2JSServiceWorker;
PWA: TProjectPas2JSProgressiveWebApp;
begin
MenuHandler:=TPas2JSMenuHandler.Create;
@ -271,8 +276,11 @@ begin
// register new-project items
RegisterProjectDescriptor(TProjectPas2JSWebApp.Create);
RegisterProjectDescriptor(TProjectPas2JSProgressiveWebApp.Create);
RegisterProjectDescriptor(TProjectPas2JSServiceWorker.Create);
PWA:=TProjectPas2JSProgressiveWebApp.Create;
RegisterProjectDescriptor(PWA);
SrvWorker:=TProjectPas2JSServiceWorker.Create;
RegisterProjectDescriptor(SrvWorker);
PWA.ServiceWorker:=SrvWorker;
RegisterProjectDescriptor(TProjectPas2JSNodeJSApp.Create);
RegisterProjectDescriptor(TProjectPas2JSModuleApp.Create);
Pas2JSHTMLClassDef:=TPas2JSHTMLClassDef.Create;
@ -313,7 +321,6 @@ function TProjectPas2JSProgressiveWebApp.FileToWebFile(aFilename: string
): string;
begin
Result:=CreateRelativePath(aFilename,WebDir);
debugln(['AAA1 TProjectPas2JSProgressiveWebApp.FileToWebFile File=',aFilename,' WebDir=',WebDir,' Result=',Result]);
Result:=FilenameToURLPath(Result);
end;
@ -338,8 +345,9 @@ end;
function TProjectPas2JSProgressiveWebApp.ShowModalOptions(
Frm: TWebBrowserProjectOptionsForm): TModalResult;
var
CurProjDir, LPRFilename: String;
CurProjDir: String;
Overwrites: TStringList;
SaveDlg: TIDESaveDialog;
function CheckOverwriteFile(aFilename: string): string;
begin
@ -364,15 +372,35 @@ begin
Result:=inherited ShowModalOptions(Frm);
if Result<>mrOk then exit;
CurProjDir:=LazSelectDirectory('Project directory');
if CurProjDir='' then exit(mrCancel);
CurProjDir:=AppendPathDelim(CleanAndExpandDirectory(CurProjDir));
ProjectDir:=CurProjDir;
SaveDlg:=IDESaveDialogClass.Create(nil);
Overwrites:=TStringList.Create;
try
LPRFilename:=CheckOverwriteFile(CurProjDir+ExtractFileName(MainSrcFileName));
CheckOverwriteFile(ChangeFileExt(LPRFilename,'.lpi'));
InitIDEFileDialog(SaveDlg);
SaveDlg.Title:='New project file (.lpr)';
SaveDlg.Filter:='Project Pascal file (*.lpr;*.pas)|*.lpr;*.pas';
if not SaveDlg.Execute then
exit(mrCancel);
MainSrcFileName:=SaveDlg.FileName;
if not FilenameIsAbsolute(MainSrcFileName) then
begin
IDEMessageDialog('Error','Please choose a file with full path.',mtError,[mbOk]);
exit(mrCancel);
end;
MainSrcFileName:=CleanAndExpandFilename(MainSrcFileName);
if CompareFileExt(MainSrcFileName,'.lpi')=0 then
MainSrcFileName:=ChangeFileExt(MainSrcFileName,'.lpr');
if ExtractFileExt(MainSrcFileName)='' then
MainSrcFileName:=MainSrcFileName+'.lpr';
CurProjDir:=ExtractFilePath(MainSrcFileName);
if CurProjDir='' then exit(mrCancel);
CurProjDir:=AppendPathDelim(CurProjDir);
ProjectDir:=CurProjDir;
CheckOverwriteFile(MainSrcFileName);
CheckOverwriteFile(ChangeFileExt(MainSrcFileName,'.lpi'));
ScriptFilename:=ExtractFileNameOnly(MainSrcFileName)+'.js';
ServiceWorkerLPR:=CheckOverwriteFile(ProjectDir+ServiceWorkerLPR);
@ -393,10 +421,10 @@ begin
end;
finally
SaveDlg.Free;
Overwrites.Free;
end;
MainSrcFileName:=LPRFilename;
if CompareFilenames(ExtractFileNameOnly(MainSrcFileName),MainSrcName)<>0 then
MainSrcName:=ExtractFileNameOnly(MainSrcFileName);
end;
@ -411,7 +439,7 @@ begin
//debugln(['Info: [TProjectPas2JSProgressiveWebApp.CreateManifestFile] "',AFileName,'"']);
Result:=AProject.CreateProjectFile(AFileName);
Result.IsPartOfProject:=true;
AProject.CustomData.Values[PJSProjectManifestFile]:=CreateRelativePath(ProjectDir,Result.Filename);
AProject.CustomData.Values[PJSProjectManifestFile]:=CreateRelativePath(Result.Filename,ProjectDir);
AProject.AddFile(Result,false);
Src:=TStringList.Create;
try
@ -615,17 +643,10 @@ end;
function TProjectPas2JSProgressiveWebApp.InitProject(AProject: TLazProject
): TModalResult;
var
CurProjDir, MainFilename, TargetFilename: String;
CompOpts: TLazCompilerOptions;
CurProjDir: String;
begin
Result:=inherited InitProject(AProject);
if Result<>mrOk then exit;
Result:=mrCancel;
// lpi
MainFilename:=AProject.MainFile.Filename;
CurProjDir:=ChompPathDelim(ExtractFilePath(MainFilename));
AProject.ProjectInfoFile:=ChangeFileExt(MainFilename,'.lpi');
CurProjDir:=ChompPathDelim(ProjectDir);
// create directories
if not FilenameIsAbsolute(CurProjDir) then
@ -633,31 +654,73 @@ begin
debugln(['Error (pas2jsdsgn): [20220403220423] TProjectPas2JSProgressiveWebApp.InitProject project directory not absolute: '+CurProjDir]);
exit;
end;
if CompareFilenames(CurProjDir,ChompPathDelim(ProjectDir))<>0 then
begin
debugln(['Error (pas2jsdsgn): [20220403221017] TProjectPas2JSProgressiveWebApp.InitProject project directory has switched: '+CurProjDir]);
exit;
end;
if not ForceDirectoriesUTF8(CurProjDir) then
if not InteractiveForceDir(CurProjDir,false) then
begin
IDEMessageDialog('Error','Unable to create directory "'+CurProjDir+'".',mtError,[mbOK]);
exit;
end;
CurProjDir:=AppendPathDelim(CurProjDir);
if not InteractiveForceDir(WebDir,true) then exit;
if not InteractiveForceDir(ImagesDir,true) then exit;
// create service worker project
AProject.ProjectInfoFile:=ChangeFileExt(ServiceWorkerLPR,'.lpi');
Result:=ServiceWorker.InitServiceWorkerProject(AProject,ServiceWorkerLPR);
if Result<>mrOk then exit;
Result:=mrOk;
end;
function TProjectPas2JSProgressiveWebApp.CreateStartFiles(AProject: TLazProject
): TModalResult;
var
CompOpts: TLazCompilerOptions;
TargetFilename, MainFilename: String;
begin
Result:=mrCancel;
// Note: InitProject has initialized the ServiceWorker project
CompOpts:=AProject.LazCompilerOptions;
TargetFilename:=AppendPathDelim(WebDir)+'ServiceWorker';
// save ServiceWorker.lpr
if not InteractiveSaveFile(ServiceWorkerLPR) then exit;
LazarusIDE.DoOpenEditorFile(ServiceWorkerLPR,-1,-1,
[ofProjectLoading,ofRegularFile]);
// save ServiceWorker.lpi
if LazarusIDE.DoSaveProject([sfQuietUnitCheck])<>mrOk then exit;
LazarusIDE.DoCloseEditorFile(ServiceWorkerLPR,[cfQuiet,cfProjectClosing]);
// delete ServiceWorker.lpr from project
if AProject.MainFileID<>0 then
raise Exception.Create('20220405231537');
AProject.MainFileID:=-1;
AProject.RemoveUnit(0,false);
AProject.CustomData.Remove(PJSProjectServiceWorker);
// initialize PWA project
AProject.ProjectInfoFile:=ChangeFileExt(MainSrcFileName,'.lpi');
// create PWA lpr and index.html
if inherited InitProject(AProject)<>mrOk then exit;
// make sure lpi has same case as lpr
MainFilename:=AProject.MainFile.Filename;
AProject.ProjectInfoFile:=ChangeFileExt(MainFilename,'.lpi');
// set PWA targetfilename
TargetFilename:=AppendPathDelim(WebDir)+MainSrcName;
CompOpts.TargetFilename:=TargetFilename;
// index.html (created in inherited InitProject)
// save index.html
if baoCreateHtml in Options then
begin
if not InteractiveSaveFile(HTMLFilename) then exit;
end;
// open lpr and index.html in source editor
if inherited CreateStartFiles(AProject)<>mrOk then exit;
// manifest.json
CreateManifestFile(AProject,ManifestFilename);
if not InteractiveSaveFile(ManifestFilename) then exit;
@ -669,20 +732,13 @@ begin
if not CopyFavIcon then exit;
if not CopyIcons then exit;
// serviceworker.lpr/lpi
// save lpr
if not InteractiveSaveFile(MainFilename) then exit;
Result:=mrOk;
end;
function TProjectPas2JSProgressiveWebApp.CreateStartFiles(AProject: TLazProject
): TModalResult;
begin
Result:=inherited CreateStartFiles(AProject);
// save lpi
LazarusIDE.DoSaveProject([sfQuietUnitCheck]);
if LazarusIDE.DoSaveProject([sfQuietUnitCheck])<>mrOk then exit;
Result:=mrOk;
end;
{ TProjectPas2JSServiceWorker }
@ -744,6 +800,26 @@ begin
end;
end;
function TProjectPas2JSServiceWorker.InitServiceWorkerProject(
AProject: TLazProject; LPRFilename: string): TModalResult;
var
MainFile: TLazProjectFile;
CompOpts: TLazCompilerOptions;
begin
MainFile:=AProject.CreateProjectFile(LPRFilename);
MainFile.IsPartOfProject:=true;
AProject.AddFile(MainFile,false);
AProject.MainFileID:=0;
CompOpts:=AProject.LazCompilerOptions;
SetDefaultServiceWorkerCompileOptions(CompOpts);
CompOpts.TargetFilename:=ExtractFileNameOnly(LPRFilename);
SetDefaultServiceWorkerRunParams(AProject.RunParameters.GetOrCreate('Default'));
AProject.MainFile.SetSourceText(CreateProjectSource,true);
AProject.CustomData.Values[PJSProject]:='1';
AProject.CustomData.Values[PJSProjectServiceWorker]:='1';
Result:=mrOk;
end;
constructor TProjectPas2JSServiceWorker.Create;
begin
inherited Create;
@ -763,22 +839,11 @@ end;
function TProjectPas2JSServiceWorker.InitProject(AProject: TLazProject
): TModalResult;
var
MainFile: TLazProjectFile;
CompOpts: TLazCompilerOptions;
begin
Result:=inherited InitProject(AProject);
MainFile:=AProject.CreateProjectFile('ServiceWorker.lpr');
MainFile.IsPartOfProject:=true;
AProject.AddFile(MainFile,false);
AProject.MainFileID:=0;
CompOpts:=AProject.LazCompilerOptions;
SetDefaultServiceWorkerCompileOptions(CompOpts);
CompOpts.TargetFilename:='ServiceWorker';
SetDefaultServiceWorkerRunParams(AProject.RunParameters.GetOrCreate('Default'));
AProject.MainFile.SetSourceText(CreateProjectSource,true);
AProject.CustomData.Values[PJSProject]:='1';
AProject.CustomData.Values[PJSProjectServiceWorker]:='1';
if Result<>mrOk then
exit;
Result:=InitServiceWorkerProject(AProject,'ServiceWorker.lpr');
end;
function TProjectPas2JSServiceWorker.CreateStartFiles(AProject: TLazProject
@ -1489,6 +1554,15 @@ begin
finally
Src.Free;
end;
HTMLFile.CustomData[PJSIsProjectHTMLFile]:='1';
if baoMaintainHTML in Options then
AProject.CustomData.Values[PJSProjectMaintainHTML]:='1';
if baoUseBrowserConsole in Options then
AProject.CustomData[PJSProjectWebBrowser]:='1';
if baoRunOnReady in options then
AProject.CustomData[PJSProjectRunAtReady]:='1';
Result:=HTMLFile;
end;
@ -1580,8 +1654,7 @@ end;
function TProjectPas2JSWebApp.InitProject(AProject: TLazProject): TModalResult;
var
MainFile,
HTMLFile : TLazProjectFile;
MainFile: TLazProjectFile;
CompOpts: TLazCompilerOptions;
begin
@ -1620,18 +1693,8 @@ begin
if baoCreateHtml in Options then
begin
debugln(['Info: [TProjectPas2JSWebApp.InitProject] HTMLFilename=',HTMLFilename]);
HTMLFile:=CreateHTMLFile(aProject,ScriptFilename);
HTMLFile.CustomData[PJSIsProjectHTMLFile]:='1';
if baoMaintainHTML in Options then
AProject.CustomData.Values[PJSProjectMaintainHTML]:='1';
if baoUseBrowserConsole in Options then
AProject.CustomData[PJSProjectWebBrowser]:='1';
if baoRunOnReady in options then
AProject.CustomData[PJSProjectRunAtReady]:='1';
CreateHTMLFile(AProject,ScriptFilename);
end;
//AProject.AddPackageDependency('pas2js_rtl');
//if baoUseBrowserApp in Options then
// AProject.AddPackageDependency('fcl_base_pas2js');
end;
function TProjectPas2JSWebApp.CreateStartFiles(AProject: TLazProject
@ -1639,12 +1702,14 @@ function TProjectPas2JSWebApp.CreateStartFiles(AProject: TLazProject
var
MainFile: TLazProjectFile;
begin
// open lpr in source editor
MainFile:=AProject.MainFile;
Result:=LazarusIDE.DoOpenEditorFile(MainFile.Filename,-1,-1,
[ofProjectLoading,ofRegularFile]);
if Result<>mrOK then
exit;
// open html in source editor
if baoCreateHtml in Options then
Result:=LazarusIDE.DoOpenEditorFile(HTMLFilename,-1,-1,
[ofProjectLoading,ofRegularFile]);

View File

@ -2,9 +2,9 @@ object Pas2JSProjectOptionsFrame: TPas2JSProjectOptionsFrame
Left = 0
Height = 372
Top = 0
Width = 495
Width = 492
ClientHeight = 372
ClientWidth = 495
ClientWidth = 492
TabOrder = 0
DesignLeft = 473
DesignTop = 400
@ -12,7 +12,7 @@ object Pas2JSProjectOptionsFrame: TPas2JSProjectOptionsFrame
Left = 12
Height = 23
Top = 8
Width = 267
Width = 250
Caption = 'Project is a Web Browser (pas2js) project'
OnChange = CBWebProjectChange
TabOrder = 0
@ -22,11 +22,12 @@ object Pas2JSProjectOptionsFrame: TPas2JSProjectOptionsFrame
AnchorSideTop.Control = CBWebProject
AnchorSideTop.Side = asrBottom
Left = 12
Height = 16
Height = 15
Top = 37
Width = 107
Width = 98
BorderSpacing.Top = 6
Caption = 'Project HTML file:'
ParentColor = False
end
object CBHTMLFile: TComboBox
AnchorSideLeft.Control = CBWebProject
@ -35,9 +36,9 @@ object Pas2JSProjectOptionsFrame: TPas2JSProjectOptionsFrame
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
Left = 12
Height = 29
Top = 55
Width = 467
Height = 30
Top = 54
Width = 464
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Top = 2
BorderSpacing.Right = 16
@ -52,7 +53,7 @@ object Pas2JSProjectOptionsFrame: TPas2JSProjectOptionsFrame
Left = 12
Height = 23
Top = 90
Width = 142
Width = 129
BorderSpacing.Top = 6
Caption = 'Maintain HTML File'
OnChange = CBMaintainHTMLFileChange
@ -65,7 +66,7 @@ object Pas2JSProjectOptionsFrame: TPas2JSProjectOptionsFrame
Left = 36
Height = 23
Top = 148
Width = 313
Width = 287
BorderSpacing.Top = 6
Caption = 'Run rtl when all page resources are fully loaded'
TabOrder = 3
@ -75,7 +76,7 @@ object Pas2JSProjectOptionsFrame: TPas2JSProjectOptionsFrame
AnchorSideTop.Control = RBStartServerAt
AnchorSideTop.Side = asrBottom
Left = 76
Height = 27
Height = 30
Top = 231
Width = 82
BorderSpacing.Left = 32
@ -92,7 +93,7 @@ object Pas2JSProjectOptionsFrame: TPas2JSProjectOptionsFrame
Left = 44
Height = 23
Top = 206
Width = 180
Width = 168
BorderSpacing.Left = 32
BorderSpacing.Top = 6
Caption = 'Start HTTP Server on port'
@ -108,9 +109,9 @@ object Pas2JSProjectOptionsFrame: TPas2JSProjectOptionsFrame
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
Left = 76
Height = 27
Top = 285
Width = 403
Height = 30
Top = 288
Width = 400
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Top = 2
BorderSpacing.Right = 16
@ -123,8 +124,8 @@ object Pas2JSProjectOptionsFrame: TPas2JSProjectOptionsFrame
AnchorSideTop.Side = asrBottom
Left = 44
Height = 23
Top = 260
Width = 173
Top = 263
Width = 161
BorderSpacing.Top = 2
Caption = 'Use this URL to start app'
OnChange = RBUseURLChange
@ -137,7 +138,7 @@ object Pas2JSProjectOptionsFrame: TPas2JSProjectOptionsFrame
Left = 12
Height = 23
Top = 177
Width = 194
Width = 182
BorderSpacing.Top = 6
Caption = 'Project needs a HTTP Server'
OnChange = CBUseHTTPServerChange
@ -150,7 +151,7 @@ object Pas2JSProjectOptionsFrame: TPas2JSProjectOptionsFrame
Left = 36
Height = 23
Top = 119
Width = 341
Width = 313
BorderSpacing.Left = 24
BorderSpacing.Top = 6
Caption = 'Use Browser Console unit to display writeln() output'
@ -161,9 +162,9 @@ object Pas2JSProjectOptionsFrame: TPas2JSProjectOptionsFrame
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 12
Height = 30
Top = 336
Width = 138
Height = 31
Top = 335
Width = 130
Anchors = [akLeft, akBottom]
AutoSize = True
BorderSpacing.Bottom = 6
@ -176,10 +177,10 @@ object Pas2JSProjectOptionsFrame: TPas2JSProjectOptionsFrame
AnchorSideLeft.Side = asrBottom
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 156
Height = 30
Top = 336
Width = 161
Left = 148
Height = 31
Top = 335
Width = 150
Anchors = [akLeft, akBottom]
AutoSize = True
BorderSpacing.Left = 6
@ -193,10 +194,10 @@ object Pas2JSProjectOptionsFrame: TPas2JSProjectOptionsFrame
AnchorSideLeft.Side = asrBottom
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 323
Height = 30
Top = 336
Width = 133
Left = 304
Height = 31
Top = 335
Width = 124
Anchors = [akLeft, akBottom]
AutoSize = True
BorderSpacing.Left = 6

View File

@ -105,7 +105,7 @@ Var
Compiler : String;
begin
DebugLn(['SetPasJSCompileOptions START']);
//DebugLn(['SetPasJSCompileOptions START']);
CompOpts.UnitOutputDirectory:='js';
CompOpts.TargetFileExt:='.js';