Skip to content

Commit 9ed26d1

Browse files
authored
Merge pull request #113 from DefactoSoftware/pien/check-file-empty
Fix error with empty style definitions json file
2 parents 425bb3a + 63a4140 commit 9ed26d1

File tree

9 files changed

+140
-45
lines changed

9 files changed

+140
-45
lines changed

README.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77

88
ExCSSModules defines two ways to read the stylesheet: embedded and read.
99

10-
If you set the `embed_stylesheet` option to the `use` macro the stylesheet definitions JSON have to be compiled before the application is compiled. This flag is used for production to optimize read times. Additionally, you can add a task to generate missing stylesheet definitions JSON files when compiling ExCSSModules, to prevent compilation errors when one of the stylesheet definitions JSON might be missing:
10+
If you set the `embed_stylesheet` option to the `use` macro the stylesheet definitions JSON have to be compiled before the application is compiled. This flag is used for production to optimize read times.
11+
12+
If you don't set the flag or set it to false, the stylesheet definition JSON files are read live from the server which creates a lot of IO for each request.
13+
14+
Additionally, you can pass a task to generate missing stylesheet definitions JSON files when compiling ExCSSModules, to prevent compilation errors when one of the stylesheet definitions JSON might be missing:
1115

1216
```ex
1317
defmodule Mix.Tasks.GenerateMissingJson do
@@ -28,7 +32,18 @@ defmodule Mix.Tasks.GenerateMissingJson do
2832
end
2933
```
3034

31-
If you don't set the flag or set it to false, the stylesheet definition JSON files are read live from the server which creates a lot of IO for each request.
35+
This task can be passed through the option `build_stylesheet_definitions_json_task`:
36+
37+
```ex
38+
use ExCSSModules.View,
39+
namespace: MyApplicationWeb,
40+
embed_stylesheet: ApplicationSettings.built_for?(:prod),
41+
build_stylesheet_definitions_json_task: unquote(Mix.Tasks.GenerateMissingJson),
42+
stylesheet:
43+
__ENV__.file
44+
|> Path.dirname()
45+
|> Path.join("./style.css")
46+
```
3247

3348
## Installation
3449
Install from [Hex.pm](https://hex.pm/packages/ex_css_modules):

lib/ex_css_modules/ex_css_modules.ex

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,24 +37,45 @@ defmodule ExCSSModules do
3737
def stylesheet(definition, build_json_task), do: read_stylesheet(definition, build_json_task)
3838

3939
defp read_stylesheet(filename, build_json_task) do
40-
cond do
41-
File.exists?(filename <> ".json") ->
42-
(filename <> ".json")
43-
|> File.read!()
44-
|> json_library().decode!()
45-
46-
build_json_task && File.exists?(filename) ->
47-
with {:ok, json_filename} <- build_json_task.run(filename: filename) do
48-
json_filename
40+
if File.exists?(filename) do
41+
cond do
42+
File.exists?("#{filename}.json") && not empty_file?("#{filename}.json") ->
43+
"#{filename}.json"
4944
|> File.read!()
5045
|> json_library().decode!()
51-
end
5246

53-
true ->
54-
%{}
47+
build_json_task ->
48+
with {:ok, json_filename} <- build_json_task.run(filename: filename) do
49+
json_filename
50+
|> File.read!()
51+
|> json_library().decode!()
52+
end
53+
54+
not File.exists?("#{filename}.json") ->
55+
message =
56+
"""
57+
File does not exist.
58+
Error compiling ExCSSModules: Be sure to build your style definitions JSON files before compiling your application.
59+
"""
60+
61+
raise(CompileError, description: message, file: "#{filename}.json")
62+
63+
empty_file?("#{filename}.json") ->
64+
message =
65+
"""
66+
File is empty.
67+
Error compiling ExCSSModules: Remove the file and/or (re)build your style definitions JSON files before compiling your application.
68+
"""
69+
70+
raise(CompileError, description: message, file: "#{filename}.json")
71+
end
72+
else
73+
%{}
5574
end
5675
end
5776

77+
defp empty_file?(filename), do: File.read!(filename) == ""
78+
5879
@doc """
5980
Reads the class definitions from the definition map and maps them to a class
6081
attribute. The `keys` argument is used to retrieve the class name or multiple

lib/ex_css_modules/view.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ defmodule ExCSSModules.View do
1111
also be enabled through the `:embed_by_default` config option.
1212
1313
If adds the following functions to the View:
14-
- stylesheet/0 - same as ExCSSModules.stylesheet/1 with the stylesheet predefined
14+
- stylesheet/0 - same as ExCSSModules.stylesheet/2 with the stylesheet predefined
1515
- class/1 - same as ExCSSModules.class/2 with the stylesheet predefined
1616
- class_name/1 - same as ExCSSModules.class_name/2 with the stylesheet predefined
1717
- class_name/2 - same as ExCSSModules.class_name/3 with the stylesheet predefined

test/ex_css_modules/view_test.exs

Lines changed: 88 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,136 @@
11
defmodule ExCSSModules.ViewTest do
22
@example_stylesheet __ENV__.file
3-
|> Path.dirname
3+
|> Path.dirname()
44
|> Path.join("../support/stylesheet.css")
55

66
use ExUnit.Case
77

8-
defmodule ViewModuleTest do
9-
use ExCSSModules.View, stylesheet: __ENV__.file
10-
|> Path.dirname
11-
|> Path.join("../support/stylesheet.css")
8+
defmodule ViewModule.Test do
9+
use ExCSSModules.View,
10+
stylesheet:
11+
__ENV__.file
12+
|> Path.dirname()
13+
|> Path.join("../support/stylesheet.css")
1214
end
1315

14-
defmodule EmbeddedViewModuleTest do
15-
use ExCSSModules.View, stylesheet: __ENV__.file
16-
|> Path.dirname
17-
|> Path.join("../support/stylesheet.css"),
18-
embed_stylesheet: true
16+
defmodule ViewModule.Embedded.Test do
17+
use ExCSSModules.View,
18+
stylesheet:
19+
__ENV__.file
20+
|> Path.dirname()
21+
|> Path.join("../support/stylesheet.css"),
22+
embed_stylesheet: true
23+
end
24+
25+
defmodule ViewModule.StylesheetDefinitions.EmptyObject.Test do
26+
use ExCSSModules.View,
27+
stylesheet:
28+
__ENV__.file
29+
|> Path.dirname()
30+
|> Path.join("../support/stylesheet_definitions_with_empty_object.css")
31+
end
32+
33+
defmodule ViewModule.StylesheetDefinitions.EmptyFile.Test do
34+
use ExCSSModules.View,
35+
stylesheet:
36+
__ENV__.file
37+
|> Path.dirname()
38+
|> Path.join("../support/empty_file.css")
39+
end
40+
41+
defmodule ViewModule.StylesheetDefinitions.NoFile.Test do
42+
use ExCSSModules.View,
43+
stylesheet:
44+
__ENV__.file
45+
|> Path.dirname()
46+
|> Path.join("../support/no_stylesheet_definitions.css")
1947
end
2048

2149
describe "stylesheet_definition/0" do
2250
test "gets the stylesheet string" do
23-
assert ViewModuleTest.stylesheet_definition
24-
== Path.expand(@example_stylesheet)
51+
assert ViewModule.Test.stylesheet_definition() ==
52+
Path.expand(@example_stylesheet)
2553
end
2654

2755
test "gets the embedded stylesheet" do
28-
assert EmbeddedViewModuleTest.stylesheet_definition
29-
== ExCSSModules.stylesheet(@example_stylesheet)
56+
assert ViewModule.Embedded.Test.stylesheet_definition() ==
57+
ExCSSModules.stylesheet(@example_stylesheet)
3058
end
3159
end
3260

3361
describe "stylesheet/0" do
3462
test "calls the stylesheet" do
35-
assert ViewModuleTest.stylesheet
36-
== ExCSSModules.stylesheet(@example_stylesheet)
63+
assert ViewModule.Test.stylesheet() ==
64+
ExCSSModules.stylesheet(@example_stylesheet)
65+
end
66+
67+
test "returns an empty map if the stylesheet definitions json file contains just an empty object" do
68+
assert ViewModule.StylesheetDefinitions.EmptyObject.Test.stylesheet() == %{}
69+
end
70+
71+
test "raises if the stylesheet definitions json file is empty" do
72+
message =
73+
"""
74+
test/support/empty_file.css.json: File is empty.
75+
Error compiling ExCSSModules: Remove the file and/or (re)build your style definitions JSON files before compiling your application.
76+
"""
77+
78+
assert_raise(CompileError, message, fn ->
79+
ViewModule.StylesheetDefinitions.EmptyFile.Test.stylesheet()
80+
end)
81+
end
82+
83+
test "raises if the stylesheet definitions json file does not exist" do
84+
message =
85+
"""
86+
test/support/no_stylesheet_definitions.css.json: File does not exist.
87+
Error compiling ExCSSModules: Be sure to build your style definitions JSON files before compiling your application.
88+
"""
89+
90+
assert_raise(CompileError, message, fn ->
91+
ViewModule.StylesheetDefinitions.NoFile.Test.stylesheet()
92+
end)
3793
end
3894
end
3995

4096
describe "class_selector/1" do
4197
test "prepends the class_name with a dot" do
42-
assert ViewModuleTest.class_selector("title") ==
43-
ExCSSModules.class_selector(@example_stylesheet, "title")
98+
assert ViewModule.Test.class_selector("title") ==
99+
ExCSSModules.class_selector(@example_stylesheet, "title")
44100
end
45101
end
46102

47103
describe "class_name/1" do
48104
test "calls the css/2 method on ExCSSModules" do
49-
assert ViewModuleTest.class_name("title") ==
50-
ExCSSModules.class_name(@example_stylesheet, "title")
105+
assert ViewModule.Test.class_name("title") ==
106+
ExCSSModules.class_name(@example_stylesheet, "title")
51107
end
52108
end
53109

54110
describe "class_name/2" do
55111
test "calls the css/3 method on ExCSSModules" do
56-
assert ViewModuleTest.class_name("title", true) ==
57-
ExCSSModules.class_name(@example_stylesheet, "title", true)
58-
assert ViewModuleTest.class_name("title", false) ==
59-
ExCSSModules.class_name(@example_stylesheet, "title", false)
112+
assert ViewModule.Test.class_name("title", true) ==
113+
ExCSSModules.class_name(@example_stylesheet, "title", true)
114+
115+
assert ViewModule.Test.class_name("title", false) ==
116+
ExCSSModules.class_name(@example_stylesheet, "title", false)
60117
end
61118
end
62119

63120
describe "class/1" do
64121
test "calls the class/2 method on ExCSSModules" do
65-
assert ViewModuleTest.class("title") ==
66-
ExCSSModules.class(@example_stylesheet, "title")
122+
assert ViewModule.Test.class("title") ==
123+
ExCSSModules.class(@example_stylesheet, "title")
67124
end
68125
end
69126

70127
describe "class/2" do
71128
test "calls the class/3 method on ExCSSModules" do
72-
assert ViewModuleTest.class("title", true) ==
73-
ExCSSModules.class(@example_stylesheet, "title", true)
74-
assert ViewModuleTest.class("title", false) ==
75-
ExCSSModules.class(@example_stylesheet, "title", false)
129+
assert ViewModule.Test.class("title", true) ==
130+
ExCSSModules.class(@example_stylesheet, "title", true)
131+
132+
assert ViewModule.Test.class("title", false) ==
133+
ExCSSModules.class(@example_stylesheet, "title", false)
76134
end
77135
end
78136
end

test/support/empty_file.css

Whitespace-only changes.

test/support/empty_file.css.json

Whitespace-only changes.

test/support/no_stylesheet_definitions.css

Whitespace-only changes.

test/support/stylesheet_definitions_with_empty_object.css

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

0 commit comments

Comments
 (0)