4
4
5
5
use Illuminate \Console \Command ;
6
6
use Illuminate \Support \Facades \File ;
7
- use Illuminate \ Support \ Str ;
7
+ use Symfony \ Component \ Console \ Terminal ;
8
8
9
9
class InstallCommand extends Command
10
10
{
@@ -16,47 +16,192 @@ class InstallCommand extends Command
16
16
17
17
protected $ description = 'Installs the Tailwind CSS scaffolding for new Laravel applications. ' ;
18
18
19
+ private $ afterMessages = [];
20
+
19
21
public function handle ()
20
22
{
21
- $ this ->info ('Installing the Tailwind CSS scaffolding... ' );
23
+ $ this ->displayHeader ('Installing TailwindCSS Laravel ' , ' <bg=blue;fg=black> INFO </> ' );
22
24
23
- $ this ->copyStubToAppIfMissing (
24
- stub: __DIR__ . '/../../stubs/tailwind.config.js ' ,
25
- to: base_path ('tailwind.config.js ' ),
26
- );
25
+ $ this ->ensureTailwindConfigExists ();
26
+ $ this ->ensureTailwindCliBinaryExists ();
27
+ $ this ->addImportStylesToLayouts ();
28
+ $ this ->addIngoreLines ();
29
+ $ this ->runFirstBuild ();
27
30
28
- $ this ->copyStubToAppIfMissing (
29
- stub: __DIR__ . '/../../stubs/resources/css/app.css ' ,
30
- to: resource_path ('css/app.css ' ),
31
- );
31
+ $ this ->displayAfterNotes ();
32
32
33
- if ($ this ->option ('download ' )) {
34
- $ this ->call ('tailwindcss:download ' , [
35
- '--cli-version ' => $ this ->option ('cli-version ' ) ?: config ('tailwindcss.version ' ),
36
- ]);
37
- } else {
38
- $ this ->info ('Done! ' );
39
- }
33
+ $ this ->newLine ();
34
+ $ this ->line (' <fg=white>Done!</> ' );
40
35
41
36
return self ::SUCCESS ;
42
37
}
43
38
39
+ private function ensureTailwindConfigExists ()
40
+ {
41
+ $ this ->displayTask ('ensuring tailwind.config.js exists ' , function () {
42
+ $ this ->copyStubToAppIfMissing (
43
+ stub: __DIR__ . '/../../stubs/tailwind.config.js ' ,
44
+ to: base_path ('tailwind.config.js ' ),
45
+ );
46
+
47
+ $ this ->copyStubToAppIfMissing (
48
+ stub: __DIR__ . '/../../stubs/resources/css/app.css ' ,
49
+ to: resource_path ('css/app.css ' ),
50
+ );
51
+
52
+ return self ::SUCCESS ;
53
+ });
54
+ }
55
+
56
+ private function ensureTailwindCliBinaryExists ()
57
+ {
58
+ if (! File::exists (config ('tailwindcss.bin_path ' )) || $ this ->option ('download ' )) {
59
+ $ this ->displayTask ('downloading the Tailwind CLI binary ' , function () {
60
+ return $ this ->callSilently ('tailwindcss:download ' , [
61
+ '--cli-version ' => $ this ->option ('cli-version ' ) ?: config ('tailwindcss.version ' ),
62
+ ]);
63
+ });
64
+ }
65
+ }
66
+
44
67
private function copyStubToAppIfMissing (string $ stub , string $ to ): void
45
68
{
46
69
if (File::exists ($ to )) {
47
- $ this ->warn (sprintf (" File %s already exists. " , $ this ->relativeOf ($ to )));
48
-
49
70
return ;
50
71
}
51
72
52
73
File::ensureDirectoryExists (dirname ($ to ));
53
74
File::copy ($ stub , $ to );
75
+ }
54
76
55
- $ this ->info (sprintf (" Created the %s file. " , $ this ->relativeOf ($ to )));
77
+ private function displayTask ($ description , $ task )
78
+ {
79
+ $ width = (new Terminal ())->getWidth ();
80
+ $ dots = max (str_repeat ('<fg=gray>.</> ' , $ width - strlen ($ description ) - 13 ), 0 );
81
+ $ this ->output ->write (sprintf (' <fg=white>%s</> %s ' , $ description , $ dots ));
82
+ $ output = $ task ();
83
+
84
+ if ($ output === self ::SUCCESS ) {
85
+ $ this ->output ->write ('<info>DONE</info> ' );
86
+ } elseif ($ output === self ::FAILURE ) {
87
+ $ this ->output ->write ('<error>FAIL</error> ' );
88
+ } elseif ($ output === self ::INVALID ) {
89
+ $ this ->output ->write ('<fg=yellow>WARN</> ' );
90
+ }
91
+
92
+ $ this ->newLine ();
93
+ }
94
+
95
+ private function displayHeader ($ text , $ prefix )
96
+ {
97
+ $ this ->newLine ();
98
+ $ this ->line (sprintf (' %s <fg=white>%s</> ' , $ prefix , $ text ));
99
+ $ this ->newLine ();
56
100
}
57
101
58
- private function relativeOf ( string $ path ): string
102
+ private function addImportStylesToLayouts ()
59
103
{
60
- return Str::after ($ path , rtrim (base_path (), '/ ' ) . '/ ' );
104
+ $ this ->displayTask ('updating layouts ' , function () {
105
+ if (File::exists (base_path ('webpack.mix.js ' ))) {
106
+ $ this ->replaceMixStylesToLayouts ();
107
+ } elseif (File::exists (base_path ('vite.config.js ' ))) {
108
+ $ this ->replaceViteStylesToLayouts ();
109
+ } else {
110
+ $ this ->appendTailwindStylesToLayouts ();
111
+ }
112
+
113
+ return self ::SUCCESS ;
114
+ });
115
+ }
116
+
117
+ private function replaceMixStylesToLayouts ()
118
+ {
119
+ $ this ->existingLayouts ()
120
+ ->each (fn ($ file ) => File::put (
121
+ $ file ,
122
+ str_replace (
123
+ "mix('css/app.css') " ,
124
+ "tailwindcss('css/app.css') " ,
125
+ File::get ($ file ),
126
+ ),
127
+ ));
128
+ }
129
+
130
+ private function replaceViteStylesToLayouts ()
131
+ {
132
+ $ this ->existingLayouts ()
133
+ ->each (fn ($ file ) => File::put (
134
+ $ file ,
135
+ preg_replace (
136
+ '/\@vite\(\[ \'resources\/css\/app.css \', \'resources\/js\/app.js \'\]\)/ ' ,
137
+ "@vite(['resources/js/app.js']) " ,
138
+ File::get ($ file ),
139
+ ),
140
+ ));
141
+
142
+ $ this ->appendTailwindStylesToLayouts ();
143
+ }
144
+
145
+ private function appendTailwindStylesToLayouts ()
146
+ {
147
+ $ this ->existingLayoutFiles ()
148
+ ->each (fn ($ file ) => File::put (
149
+ $ file ,
150
+ preg_replace (
151
+ '/(\s*)(<\/head>)/ ' ,
152
+ "\\1 <link rel= \"stylesheet \" href= \"{{ tailwindcss('css/app.css') }} \"> \n\\1 \\2 " ,
153
+ File::get ($ file ),
154
+ ),
155
+ ));
156
+ }
157
+
158
+ private function existingLayoutFiles ()
159
+ {
160
+ return collect (['app ' , 'guest ' ])
161
+ ->map (fn ($ file ) => resource_path ("views/layouts/ {$ file }.blade.php " ))
162
+ ->filter (fn ($ file ) => File::exists ($ file ));
163
+ }
164
+
165
+ private function addIngoreLines ()
166
+ {
167
+ $ this ->displayTask ('adding ignore lines ' , function () {
168
+ $ binary = basename (config ('tailwindcss.bin_path ' ));
169
+
170
+ File::append (base_path ('.gitignore ' ), <<<LINES
171
+
172
+ /public/css/
173
+ /public/dist/
174
+ .tailwindcss-manifest.json
175
+ {$ binary }
176
+ LINES );
177
+
178
+ return self ::SUCCESS ;
179
+ });
180
+ }
181
+
182
+ private function runFirstBuild ()
183
+ {
184
+ $ this ->displayTask ('running first build ' , function () {
185
+ $ result = $ this ->callSilently ('tailwindcss:build ' );
186
+
187
+ if ($ result !== self ::SUCCESS ) {
188
+ $ this ->afterMessages [] = '<fg=white>* Try running `<fg=yellow>php artisan tailwindcss:build</>`</> ' ;
189
+
190
+ return self ::INVALID ;
191
+ }
192
+
193
+ return self ::SUCCESS ;
194
+ });
195
+ }
196
+
197
+ private function displayAfterNotes ()
198
+ {
199
+ if (count ($ this ->afterMessages ) > 0 ) {
200
+ $ this ->displayHeader ('After Notes & Next Steps ' , '<bg=yellow;fg=black> NOTES </> ' );
201
+
202
+ foreach ($ this ->afterMessages as $ message ) {
203
+ $ this ->line (' ' .$ message );
204
+ }
205
+ }
61
206
}
62
207
}
0 commit comments