From 35d375867841924a9b11813a9b9341ed51ea2fa1 Mon Sep 17 00:00:00 2001 From: Denys Pacheco Date: Wed, 26 Jan 2022 11:57:41 -0300 Subject: [PATCH] minify and organize --- .gitignore | 1 + README.md | 16 ++- config.json | 8 +- convert.py | 144 +++-------------------- css/newstyle-hashed.css | 4 - examples/css/newstyle-hashed.css | 1 + {css => examples/css}/newstyle.css | 0 examples/htmls/another-hashed.html | 1 + {htmls => examples/htmls}/another.html | 0 examples/index-hashed.html | 1 + index.html => examples/index.html | 0 examples/style-hashed.css | 1 + style.css => examples/style.css | 0 functions.py | 155 +++++++++++++++++++++++++ htmls/another-hashed.html | 23 ---- index-hashed.html | 38 ------ style-hashed.css | 22 ---- 17 files changed, 193 insertions(+), 222 deletions(-) delete mode 100644 css/newstyle-hashed.css create mode 100644 examples/css/newstyle-hashed.css rename {css => examples/css}/newstyle.css (100%) create mode 100644 examples/htmls/another-hashed.html rename {htmls => examples/htmls}/another.html (100%) create mode 100644 examples/index-hashed.html rename index.html => examples/index.html (100%) create mode 100644 examples/style-hashed.css rename style.css => examples/style.css (100%) create mode 100644 functions.py delete mode 100644 htmls/another-hashed.html delete mode 100644 index-hashed.html delete mode 100644 style-hashed.css diff --git a/.gitignore b/.gitignore index ad1c1a5..b0f8abf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .vscode .pytest_cache test.py +__pycache__ diff --git a/README.md b/README.md index 2c39ba9..0db2d09 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Css Hashfy Converter +# Css Hashfy Minify Converter This is a python script to hashfy css classes. It was inspired on Google's approach to minimize classes names to faster load web pages. @@ -6,10 +6,12 @@ It was inspired on Google's approach to minimize classes names to faster load we ## What it does - [x] Make a hash out of css and id classes +- [x] Make a random hash each run +- [x] Minify your css - [x] Auto apply for all the html files - [x] Create `-hashed` file with the output -- [x] Auto change the css file to `-hashed` in the html link tag -- [x] Multiple files on multiple folders +- [x] Auto change the css file names to `-hashed` in the html link tag +- [x] Multiple files on multiple folders (top-down) ## Usage @@ -19,10 +21,14 @@ It will search all files with the extensions marked on the configuration file. It will give the output with `foo-hashed.html` and `foo-hashed.css`. + ### Configure Change in the [configuration file](/config.json) the directories to be ignored, hash length and overwrite files. -## To Change? +**Mind that: if `overwrite` is `false` the hash will not be equal to the old files, therefore not in sync.** + +## What to come -- [ ] Separation of classes and ids in prefix +- [ ] Obfuscate everything? +- [ ] How about js too? diff --git a/config.json b/config.json index 176d79f..8f9a3a0 100644 --- a/config.json +++ b/config.json @@ -6,15 +6,17 @@ "filesIgnore": [ "-hashed" ], - "dirsIgnore":[ + "dirsIgnore": [ ".", "packages", "src", "dist" ], "extCopy": "-hashed", - "patternCSS": "[\\.\\#]-?[_a-zA-Z]+[_a-zA-Z0-9-]*\\s*\\{", + "patternCSS": "[\\.\\#]-?([_a-zA-Z]+[_a-zA-Z0-9-]*)\\s*\\{", "patternHTML": "class[\t]*=[\t]*\"[^\"]+", "hashLength": 6, - "overwriteFiles": false + "overwriteFiles": false, + "minimize": true, + "output": true } \ No newline at end of file diff --git a/convert.py b/convert.py index 5cfb527..d6c6db2 100644 --- a/convert.py +++ b/convert.py @@ -1,145 +1,35 @@ import os -import json -import re -from os import listdir -from os.path import isfile, join +from functions import * +config, _PATH = loadconfig() -def read(file): - with open(file, 'r') as f: - lines = f.readlines() - f.close() - return lines - - -def write(root, new_name, lines): - with open(os.path.join(root, new_name), 'w') as exf: - exf.writelines(lines) - exf.close() - - -def getVars(file, config): - # Get the extension and use as a flag e.g.: HTML, CSS... - pattern_file = file.split('.')[1].upper() - - lines = read(file) - - # Use the right regex to find the classes on the file - substring = re.findall(config['pattern' + pattern_file], str(lines)) - - name, ext = file.split('.') - new_name = name + config['extCopy'] + '.' + ext - - return new_name, substring +search_files = lookfiles() def main(): - # Load config.json - with open("config.json") as json_data_file: - config = json.load(json_data_file) - _PATH = os.getcwd() + '/' - - search_files = [] - # Look for files - for root, subdirectories, files in os.walk(_PATH): - # Comprehension to break outter loop - if any([dirsIgnore for dirsIgnore in config['dirsIgnore'] if dirsIgnore in root]): - continue + search_files = lookfiles() - # And all its files - for index, file in enumerate(files): - for filesSearch in config['filesSearch']: - for filesIgnore in config['filesIgnore']: - if(filesSearch in file and filesIgnore not in file): - search_files.append((root, file)) + if(config['output']): - #print(f'files: {search_files}\n') + #print(f'files: {search_files}\n') - print('CSS Hashfy found files:', end='\n\n') - for root, file in search_files: - print(os.path.join(root, file)) - print() + print('CSS Hashfy found files:', end='\n\n') + for root, file in search_files: + print(os.path.join(root, file)) + print() - print('Starting hashing...', end='\n\n') + print('Starting hashing...', end='\n\n') # Initializing alg vars - count = 0 - classes_dict = {} - - # Get all the files with the '.css' extension - css_files = [(root, file) - for root, file in search_files if file.endswith('.css')] - - # Copy the files of the search - for root, file in css_files: - lines = read(os.path.join(root, file)) - - new_name, substring = getVars(os.path.join(root, file), config) - - # If the file doesn't exist, create a new one - if(config['overwriteFiles'] or not isfile(join(root, new_name))): - substring = [s.translate({ord('.'): None, ord( - '{'): None, ord('#'): None}).strip() for s in substring] - - # Create the dictionary with the classe's hashes of the CSS - classes_dict.update( - {s: str(abs(hash(s)) % (10 ** config['hashLength'])) for s in substring}) - - # CSS WRITE - - # Copy the hashes to the copied lines of the file - for index, l in enumerate(lines): - for k, v in classes_dict.items(): - if k in l: - l = l.replace(k, 'c'+v) - lines[index] = l - - write(root, new_name, lines) - count += 1 - print(f"{10*'*'} \t {new_name.split('/')[-1]} \t {10*'*'}") - - # If it exists, pass - else: - print(f'!! file already existed: {new_name}') - - # Overwrite HTML classes - html_files = [(root, file) - for root, file in search_files if file.endswith('.html')] - - # Copy the files of the search - for root, file in html_files: - lines = read(os.path.join(root, file)) - - new_name, substring = getVars(os.path.join(root, file), config) - - # HTML WRITE - - # HTML overwrite link tags - if(config['overwriteFiles'] or not isfile(join(root, new_name))): - for index, l in enumerate(lines): - for root, file in css_files: - if file in l and 'link' in l: - l = l.replace( - file, f"{file.split('.')[0]}{config['extCopy']}.css") - lines[index] = l - - # Overwrite html lines with the hashed css classes - for index, l in enumerate(lines): - for k, v in classes_dict.items(): - if k in l: - l = l.replace(k, 'c'+v) - lines[index] = l + classes_dict, css_files, css_count = csshash(search_files) - write(root, new_name, lines) - count += 1 - print(f"{10*'*'} \t {new_name.split('/')[-1]} \t {10*'*'}") + html_count = htmlhash(search_files, classes_dict, css_files) - # If it exists, pass - else: - print(f'!! file already existed: {new_name}') + if(config['output']): - print() - print(f'finished! {str(int(count/len(search_files))*100)}% done.') + print() + print( + f'finished! {str(int((html_count + css_count)/len(search_files))*100)}% done.') main() diff --git a/css/newstyle-hashed.css b/css/newstyle-hashed.css deleted file mode 100644 index 1e0271e..0000000 --- a/css/newstyle-hashed.css +++ /dev/null @@ -1,4 +0,0 @@ -.c427219 { - color: black; - background-color: aqua; -} diff --git a/examples/css/newstyle-hashed.css b/examples/css/newstyle-hashed.css new file mode 100644 index 0000000..154641b --- /dev/null +++ b/examples/css/newstyle-hashed.css @@ -0,0 +1 @@ +.c472338{color:black;background-color:aqua;} \ No newline at end of file diff --git a/css/newstyle.css b/examples/css/newstyle.css similarity index 100% rename from css/newstyle.css rename to examples/css/newstyle.css diff --git a/examples/htmls/another-hashed.html b/examples/htmls/another-hashed.html new file mode 100644 index 0000000..bbead35 --- /dev/null +++ b/examples/htmls/another-hashed.html @@ -0,0 +1 @@ +Document

AnotherTestofhtml

\ No newline at end of file diff --git a/htmls/another.html b/examples/htmls/another.html similarity index 100% rename from htmls/another.html rename to examples/htmls/another.html diff --git a/examples/index-hashed.html b/examples/index-hashed.html new file mode 100644 index 0000000..8a6d694 --- /dev/null +++ b/examples/index-hashed.html @@ -0,0 +1 @@ +DocumentThisisatextofahtml

testofanotherkind
  • Listicons
  • canbeused
  • asbullets
  • inlists
  • \ No newline at end of file diff --git a/index.html b/examples/index.html similarity index 100% rename from index.html rename to examples/index.html diff --git a/examples/style-hashed.css b/examples/style-hashed.css new file mode 100644 index 0000000..026fbe6 --- /dev/null +++ b/examples/style-hashed.css @@ -0,0 +1 @@ +.c892938{text-align:center!important;}.c328534{font-size:calc(1.475rem+2.7vw);font-weight:300;line-height:1.2;}.c65182{background-color:greenyellow;}.c209394{background-color:red;}#c627821{width:max-content;margin:auto;} \ No newline at end of file diff --git a/style.css b/examples/style.css similarity index 100% rename from style.css rename to examples/style.css diff --git a/functions.py b/functions.py new file mode 100644 index 0000000..6ef8254 --- /dev/null +++ b/functions.py @@ -0,0 +1,155 @@ +import os +import json +import re +from os.path import isfile, join + + +def loadconfig(): + # Load config.json + with open("config.json") as json_data_file: + config = json.load(json_data_file) + _PATH = os.getcwd() + '/' + + return config, _PATH + + +config, _PATH = loadconfig() + + +def read(file): + with open(file, 'r') as f: + lines = f.readlines() + f.close() + return lines + + +def write(root, new_name, lines): + with open(os.path.join(root, new_name), 'w') as exf: + exf.writelines(lines) + exf.close() + + +def getvars(file): + # Get the extension and use as a flag e.g.: HTML, CSS... + pattern_file = file.split('.')[1].upper() + + lines = read(file) + + # Use the right regex to find the classes on the file + substring = re.findall(config['pattern' + pattern_file], str(lines)) + + name, ext = file.split('.') + new_name = name + config['extCopy'] + '.' + ext + + return new_name, substring + + +def lookfiles(): + search_files = [] + # Look for files + for root, subdirectories, files in os.walk(_PATH): + # Comprehension to break outter loop + if any([dirsIgnore for dirsIgnore in config['dirsIgnore'] if dirsIgnore in root]): + continue + + # And all its files + for index, file in enumerate(files): + for filesSearch in config['filesSearch']: + for filesIgnore in config['filesIgnore']: + if(filesSearch in file and filesIgnore not in file): + search_files.append((root, file)) + + return search_files + + +def csshash(search_files): + + classes_dict = {} + count = 0 + + # Get all the files with the '.css' extension + css_files = [(root, file) + for root, file in search_files if file.endswith('.css')] + + # Copy the files of the search + for root, file in css_files: + lines = read(os.path.join(root, file)) + + new_name, substring = getvars(os.path.join(root, file)) + + # If the file doesn't exist, create a new one + if(config['overwriteFiles'] or not isfile(join(root, new_name))): + + # Create the dictionary with the classe's hashes of the CSS + classes_dict.update( + {s: str(abs(hash(s)) % (10 ** config['hashLength'])) for s in substring}) + + # CSS WRITE + + # Copy the hashes to the copied lines of the file + for index, l in enumerate(lines): + for k, v in classes_dict.items(): + if k in l: + l = l.replace(k, 'c'+v) + if(config['minimize']): + lines[index] = ''.join(l.split()) + else: + lines[index] = l + + write(root, new_name, lines) + count += 1 + if(config['output']): + print(f"{10*'*'} \t {new_name.split('/')[-1]} \t {10*'*'}") + + # If it exists, pass + else: + print(f'!! file already existed: {new_name}') + + return classes_dict, css_files, count + + +def htmlhash(search_files, classes_dict, css_files): + + count = 0 + + # Overwrite HTML classes + html_files = [(root, file) + for root, file in search_files if file.endswith('.html')] + + # Copy the files of the search + for root, file in html_files: + lines = read(os.path.join(root, file)) + + new_name, substring = getvars(os.path.join(root, file)) + + # HTML WRITE + + # HTML overwrite link tags + if(config['overwriteFiles'] or not isfile(join(root, new_name))): + for index, l in enumerate(lines): + for root, file in css_files: + if file in l and 'link' in l: + l = l.replace( + file, f"{file.split('.')[0]}{config['extCopy']}.css") + lines[index] = l + + # Overwrite html lines with the hashed css classes + for index, l in enumerate(lines): + for k, v in classes_dict.items(): + if k in l: + l = l.replace(k, 'c'+v) + if(config['minimize']): + lines[index] = ''.join(l.split()) + else: + lines[index] = l + + write(root, new_name, lines) + count += 1 + if(config['output']): + print(f"{10*'*'} \t {new_name.split('/')[-1]} \t {10*'*'}") + + # If it exists, pass + else: + print(f'!! file already existed: {new_name}') + + return count diff --git a/htmls/another-hashed.html b/htmls/another-hashed.html deleted file mode 100644 index 85bce4e..0000000 --- a/htmls/another-hashed.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - Document - - - - -
    -

    Another Test of html

    -
    - - - - \ No newline at end of file diff --git a/index-hashed.html b/index-hashed.html deleted file mode 100644 index a52447d..0000000 --- a/index-hashed.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - Document - - - - -
    -

    This is a text of a html

    -
    - -
    -
    - test of another kind -
    -
    - -
    - -
      -
    • List icons
    • -
    • can be used
    • -
    • as bullets
    • -
    • in lists
    • -
    -
    - - - - \ No newline at end of file diff --git a/style-hashed.css b/style-hashed.css deleted file mode 100644 index 31221fe..0000000 --- a/style-hashed.css +++ /dev/null @@ -1,22 +0,0 @@ -.c538942 { - text-align: center !important; -} - -.c69861 { - font-size: calc(1.475rem + 2.7vw); - font-weight: 300; - line-height: 1.2; -} - -.c247297 { - background-color: greenyellow; -} - -.c496546 { - background-color: red; -} - -#c501666 { - width: max-content; - margin: auto; -}