├── .editorconfig ├── .git-blame-ignore-revs ├── .github └── workflows │ ├── pypi-publish.yml │ └── tests.yml ├── .gitignore ├── AUTHORS.rst ├── CHANGES.rst ├── CONTRIBUTING.rst ├── INSTALL.rst ├── LICENSE ├── MANIFEST.in ├── README.rst ├── docs ├── Makefile ├── api.rst ├── authors.rst ├── changes.rst ├── conf.py ├── configuration.rst ├── contributing.rst ├── index.rst ├── installation.rst ├── license.rst ├── make.bat ├── requirements.txt └── usage.rst ├── flask_webpackext ├── __init__.py ├── bundle.py ├── cli.py ├── config.py ├── errors.py ├── ext.py ├── manifest.py ├── project.py └── proxies.py ├── pyproject.toml ├── requirements-devel.txt ├── run-tests.sh ├── setup.cfg ├── setup.py └── tests ├── assets ├── index.js ├── package.json └── webpack.config.js ├── assetsbundle ├── package.json └── webpack.config.js ├── bundle1 └── app1.js ├── bundle2 └── app2.js ├── conftest.py ├── manifest.json ├── test_cli.py ├── test_ext.py ├── test_manifest.py └── test_project.py /.editorconfig: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017 CERN. 5 | # 6 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 7 | # it under the terms of the Revised BSD License; see LICENSE file for 8 | # more details. 9 | 10 | root = true 11 | 12 | [*] 13 | indent_style = space 14 | end_of_line = lf 15 | insert_final_newline = true 16 | trim_trailing_whitespace = true 17 | charset = utf-8 18 | 19 | # RST files (used by sphinx) 20 | [*.rst] 21 | indent_size = 4 22 | 23 | # CSS, HTML, JS, JSON, YML 24 | [*.{css,html,js,json,yml}] 25 | indent_size = 2 26 | 27 | # Matches the exact files either package.json or .travis.yml 28 | [{package.json,.travis.yml}] 29 | indent_size = 2 30 | 31 | # Dockerfile 32 | [Dockerfile] 33 | indent_size = 4 34 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | 9f49a82b64ebec8e5231e0d0de313daacc511b31 2 | -------------------------------------------------------------------------------- /.github/workflows/pypi-publish.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2024 Graz University of Technology. 4 | # 5 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 6 | # it under the terms of the Revised BSD License; see LICENSE file for 7 | # more details. 8 | 9 | name: Publish 10 | 11 | on: 12 | push: 13 | tags: 14 | - v* 15 | 16 | jobs: 17 | publish: 18 | uses: inveniosoftware/workflows/.github/workflows/pypi-publish.yml@master 19 | secrets: inherit 20 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2024 Graz University of Technology. 4 | # 5 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 6 | # it under the terms of the Revised BSD License; see LICENSE file for 7 | # more details. 8 | 9 | name: CI 10 | 11 | on: 12 | push: 13 | branches: 14 | - master 15 | pull_request: 16 | branches: 17 | - master 18 | schedule: 19 | # * is a special character in YAML so you have to quote this string 20 | - cron: "0 3 * * 6" 21 | workflow_dispatch: 22 | inputs: 23 | reason: 24 | description: "Reason" 25 | required: false 26 | default: "Manual trigger" 27 | 28 | jobs: 29 | tests: 30 | uses: inveniosoftware/workflows/.github/workflows/tests-python.yml@master 31 | with: 32 | db-service: '[""]' 33 | search-service: '[""]' 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # Idea software family 6 | .idea/ 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | env/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *,cover 47 | 48 | # Translations 49 | *.mo 50 | 51 | # Django stuff: 52 | *.log 53 | 54 | # Sphinx documentation 55 | docs/_build/ 56 | 57 | # PyBuilder 58 | target/ 59 | 60 | # Vim swapfiles 61 | .*.sw? 62 | 63 | node_modules/ 64 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | Authors 2 | ======= 3 | 4 | - Lars Holm Nielsen 5 | -------------------------------------------------------------------------------- /CHANGES.rst: -------------------------------------------------------------------------------- 1 | Changes 2 | ======= 3 | 4 | Version 2.1.0 (released 2025-03-28) 5 | 6 | - Take keyword args to projects and pass them to the super constructor 7 | - Add ``WEBPACKEXT_NPM_PKG_CLS`` variable to set the class to use for ``project.npmpkg`` 8 | 9 | Version 2.0.0 (released 2024-11-28) 10 | 11 | - Project: allows passing allowed_copy_paths to copy assets when building with 12 | Webpack 13 | - Package structure update. 14 | - Added ``black`` formatting. 15 | - Dropped Python 3.6 support. 16 | 17 | Version 1.0.2 (released 2020-05-13) 18 | 19 | - Deprecated Python versions lower than 3.6.0. Now supporting 3.6.0 and 3.7.0 20 | - Set Sphinx ``<3`` because of errors related to application context 21 | - Stop using example app 22 | 23 | Version 1.0.1 (released 2018-12-14) 24 | 25 | - Pypi classifier and deployment configuration 26 | - License detection 27 | 28 | Version 0.1.0 (released 2016-05-29) 29 | 30 | - Initial public release. 31 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | Contributions are welcome, and they are greatly appreciated! Every 5 | little bit helps, and credit will always be given. 6 | 7 | Types of Contributions 8 | ---------------------- 9 | 10 | Report Bugs 11 | ~~~~~~~~~~~ 12 | 13 | Report bugs at https://github.com/inveniosoftware/flask-webpackext/issues. 14 | 15 | If you are reporting a bug, please include: 16 | 17 | * Your operating system name and version. 18 | * Any details about your local setup that might be helpful in troubleshooting. 19 | * Detailed steps to reproduce the bug. 20 | 21 | Fix Bugs 22 | ~~~~~~~~ 23 | 24 | Look through the GitHub issues for bugs. Anything tagged with "bug" 25 | is open to whoever wants to implement it. 26 | 27 | Implement Features 28 | ~~~~~~~~~~~~~~~~~~ 29 | 30 | Look through the GitHub issues for features. Anything tagged with "feature" 31 | is open to whoever wants to implement it. 32 | 33 | Write Documentation 34 | ~~~~~~~~~~~~~~~~~~~ 35 | 36 | Flask-WebpackExt could always use more documentation, whether as part of the 37 | official Flask-WebpackExt docs, in docstrings, or even on the web in blog posts, 38 | articles, and such. 39 | 40 | Submit Feedback 41 | ~~~~~~~~~~~~~~~ 42 | 43 | The best way to send feedback is to file an issue at 44 | https://github.com/inveniosoftware/flask-webpackext/issues. 45 | 46 | If you are proposing a feature: 47 | 48 | * Explain in detail how it would work. 49 | * Keep the scope as narrow as possible, to make it easier to implement. 50 | * Remember that this is a volunteer-driven project, and that contributions 51 | are welcome :) 52 | 53 | Get Started! 54 | ------------ 55 | 56 | Ready to contribute? Here's how to set up `flask-webpackext` for local development. 57 | 58 | 1. Fork the `inveniosoftware/flask-webpackext` repo on GitHub. 59 | 2. Clone your fork locally: 60 | 61 | .. code-block:: console 62 | 63 | $ git clone git@github.com:your_name_here/flask-webpackext.git 64 | 65 | 3. Install your local copy into a virtualenv. Assuming you have 66 | virtualenvwrapper installed, this is how you set up your fork for local 67 | development: 68 | 69 | .. code-block:: console 70 | 71 | $ mkvirtualenv flask-webpackext 72 | $ cd flask-webpackext/ 73 | $ pip install -e .[all] 74 | 75 | 4. Create a branch for local development: 76 | 77 | .. code-block:: console 78 | 79 | $ git checkout -b name-of-your-bugfix-or-feature 80 | 81 | Now you can make your changes locally. 82 | 83 | 5. When you're done making changes, check that your changes pass tests: 84 | 85 | .. code-block:: console 86 | 87 | $ ./run-tests.sh 88 | 89 | The tests will provide you with test coverage and also check PEP8 90 | (code style), PEP257 (documentation), flake8 as well as build the Sphinx 91 | documentation and run doctests. 92 | 93 | 6. Commit your changes and push your branch to GitHub: 94 | 95 | .. code-block:: console 96 | 97 | $ git add . 98 | $ git commit -s 99 | -m "component: title without verbs" 100 | -m "* NEW Adds your new feature." 101 | -m "* FIX Fixes an existing issue." 102 | -m "* BETTER Improves and existing feature." 103 | -m "* Changes something that should not be visible in release notes." 104 | $ git push origin name-of-your-bugfix-or-feature 105 | 106 | 7. Submit a pull request through the GitHub website. 107 | 108 | Pull Request Guidelines 109 | ----------------------- 110 | 111 | Before you submit a pull request, check that it meets these guidelines: 112 | 113 | 1. The pull request should include tests and must not decrease test coverage. 114 | 2. If the pull request adds functionality, the docs should be updated. Put 115 | your new functionality into a function with a docstring. 116 | 3. The pull request should work for Python 2.7, 3.3, 3.4 and 3.5. Check 117 | https://travis-ci.org/inveniosoftware/flask-webpackext/pull_requests 118 | and make sure that the tests pass for all supported Python versions. 119 | -------------------------------------------------------------------------------- /INSTALL.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | Flask-WebpackExt is on PyPI so all you need is: 5 | 6 | .. code-block:: console 7 | 8 | $ pip install flask-webpackext 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Flask-WebpackExt is free software; you can redistribute it and/or modify it 2 | under the terms of the Revised BSD License quoted below. 3 | 4 | Copyright (C) 2017-2018 CERN. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are 8 | met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 28 | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 29 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 30 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 31 | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 32 | DAMAGE. 33 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017 CERN. 5 | # 6 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 7 | # it under the terms of the Revised BSD License; see LICENSE file for 8 | # more details. 9 | 10 | include .editorconfig 11 | include *.rst 12 | include *.sh 13 | include *.txt 14 | include LICENSE 15 | include pytest.ini 16 | prune docs/_build 17 | recursive-include docs *.bat 18 | recursive-include docs *.py 19 | recursive-include docs *.rst 20 | recursive-include docs *.txt 21 | recursive-include docs Makefile 22 | recursive-include tests *.js 23 | recursive-include tests *.json 24 | recursive-include tests *.py 25 | include .git-blame-ignore-revs 26 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ================== 2 | Flask-WebpackExt 3 | ================== 4 | 5 | .. image:: https://img.shields.io/travis/inveniosoftware/flask-webpackext.svg 6 | :target: https://travis-ci.org/inveniosoftware/flask-webpackext 7 | 8 | .. image:: https://img.shields.io/coveralls/inveniosoftware/flask-webpackext.svg 9 | :target: https://coveralls.io/r/inveniosoftware/flask-webpackext 10 | 11 | .. image:: https://img.shields.io/github/tag/inveniosoftware/flask-webpackext.svg 12 | :target: https://github.com/inveniosoftware/flask-webpackext/releases 13 | 14 | .. image:: https://img.shields.io/pypi/dm/flask-webpackext.svg 15 | :target: https://pypi.python.org/pypi/flask-webpackext 16 | 17 | .. image:: https://img.shields.io/github/license/inveniosoftware/flask-webpackext.svg 18 | :target: https://github.com/inveniosoftware/flask-webpackext/blob/master/LICENSE 19 | 20 | Webpack integration for Flask. 21 | 22 | Flask-WebpackExt makes it easy to interface with your existing Webpack project 23 | from Flask and does not try to manage Webpack for you. Flask-WebpackExt does 24 | this via: 25 | 26 | * **Manifests**: You tell Webpack to write a ``manifest.json`` using plugins 27 | such as `webpack-manifest-plugin 28 | `_, 29 | `webpack-yam-plugin 30 | `_ or 31 | `webpack-bundle-tracker 32 | `_. Flask-WebpackExt 33 | reads the manifest and makes your compiled assets available in your Jinja 34 | templates. 35 | * **CLI for NPM**: Flask-WebpackExt provides a Flask CLI so that e.g. 36 | ``flask webpack install`` will run ``npm install`` in your Webpack project. 37 | Similarly, ``flask webpack build`` will run ``npm run build``. 38 | 39 | Optionally you can use Flask-WebpackExt to also: 40 | 41 | * **Inject configuration:** Flask-WebpackExt will write a ``config.json`` into 42 | your Webpack project, which you can import in your Webpack configuration. You 43 | define what goes in the config e.g. Let Webpack know about output paths or 44 | dynamic entry points. 45 | * **Collect bundles:** If your Webpack project is spread over multiple Python 46 | packages, Flask-WebpackExt can help you dynamically assemble the files into a 47 | Webpack project. This is useful if you don't know until runtime which 48 | packages are installed. 49 | 50 | Further documentation is available on 51 | https://flask-webpackext.readthedocs.io/ 52 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " applehelp to make an Apple Help Book" 34 | @echo " devhelp to make HTML files and a Devhelp project" 35 | @echo " epub to make an epub" 36 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 37 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 38 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 39 | @echo " text to make text files" 40 | @echo " man to make manual pages" 41 | @echo " texinfo to make Texinfo files" 42 | @echo " info to make Texinfo files and run them through makeinfo" 43 | @echo " gettext to make PO message catalogs" 44 | @echo " changes to make an overview of all changed/added/deprecated items" 45 | @echo " xml to make Docutils-native XML files" 46 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 47 | @echo " linkcheck to check all external links for integrity" 48 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 49 | @echo " coverage to run coverage check of the documentation (if enabled)" 50 | 51 | clean: 52 | rm -rf $(BUILDDIR)/* 53 | 54 | html: 55 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 56 | @echo 57 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 58 | 59 | dirhtml: 60 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 61 | @echo 62 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 63 | 64 | singlehtml: 65 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 66 | @echo 67 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 68 | 69 | pickle: 70 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 71 | @echo 72 | @echo "Build finished; now you can process the pickle files." 73 | 74 | json: 75 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 76 | @echo 77 | @echo "Build finished; now you can process the JSON files." 78 | 79 | htmlhelp: 80 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 81 | @echo 82 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 83 | ".hhp project file in $(BUILDDIR)/htmlhelp." 84 | 85 | qthelp: 86 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 87 | @echo 88 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 89 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 90 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Flask-WebpackExt.qhcp" 91 | @echo "To view the help file:" 92 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Flask-WebpackExt.qhc" 93 | 94 | applehelp: 95 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 96 | @echo 97 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 98 | @echo "N.B. You won't be able to view it unless you put it in" \ 99 | "~/Library/Documentation/Help or install it in your application" \ 100 | "bundle." 101 | 102 | devhelp: 103 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 104 | @echo 105 | @echo "Build finished." 106 | @echo "To view the help file:" 107 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Flask-WebpackExt" 108 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Flask-WebpackExt" 109 | @echo "# devhelp" 110 | 111 | epub: 112 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 113 | @echo 114 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 115 | 116 | latex: 117 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 118 | @echo 119 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 120 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 121 | "(use \`make latexpdf' here to do that automatically)." 122 | 123 | latexpdf: 124 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 125 | @echo "Running LaTeX files through pdflatex..." 126 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 127 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 128 | 129 | latexpdfja: 130 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 131 | @echo "Running LaTeX files through platex and dvipdfmx..." 132 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 133 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 134 | 135 | text: 136 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 137 | @echo 138 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 139 | 140 | man: 141 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 142 | @echo 143 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 144 | 145 | texinfo: 146 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 147 | @echo 148 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 149 | @echo "Run \`make' in that directory to run these through makeinfo" \ 150 | "(use \`make info' here to do that automatically)." 151 | 152 | info: 153 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 154 | @echo "Running Texinfo files through makeinfo..." 155 | make -C $(BUILDDIR)/texinfo info 156 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 157 | 158 | gettext: 159 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 160 | @echo 161 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 162 | 163 | changes: 164 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 165 | @echo 166 | @echo "The overview file is in $(BUILDDIR)/changes." 167 | 168 | linkcheck: 169 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 170 | @echo 171 | @echo "Link check complete; look for any errors in the above output " \ 172 | "or in $(BUILDDIR)/linkcheck/output.txt." 173 | 174 | doctest: 175 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 176 | @echo "Testing of doctests in the sources finished, look at the " \ 177 | "results in $(BUILDDIR)/doctest/output.txt." 178 | 179 | coverage: 180 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 181 | @echo "Testing of coverage in the sources finished, look at the " \ 182 | "results in $(BUILDDIR)/coverage/python.txt." 183 | 184 | xml: 185 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 186 | @echo 187 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 188 | 189 | pseudoxml: 190 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 191 | @echo 192 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 193 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | API Docs 2 | ======== 3 | 4 | .. automodule:: flask_webpackext.ext 5 | :members: 6 | 7 | Manifest 8 | -------- 9 | 10 | .. automodule:: flask_webpackext.manifest 11 | :members: 12 | 13 | Project 14 | ------- 15 | 16 | .. automodule:: flask_webpackext.project 17 | :members: 18 | 19 | Bundle 20 | ------ 21 | 22 | .. automodule:: flask_webpackext.bundle 23 | :members: 24 | 25 | Command Line Interface 26 | ---------------------- 27 | 28 | .. click:: flask_webpackext.cli:webpack 29 | :prog: flask webpack 30 | :show-nested: 31 | -------------------------------------------------------------------------------- /docs/authors.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../AUTHORS.rst 2 | -------------------------------------------------------------------------------- /docs/changes.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CHANGES.rst 2 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017 CERN. 5 | # Copyright (C) 2024 Graz University of Technology. 6 | # 7 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 8 | # it under the terms of the Revised BSD License; see LICENSE file for 9 | # more details. 10 | 11 | """Sphinx configuration.""" 12 | 13 | from flask_webpackext import __version__ 14 | 15 | # -- General configuration ------------------------------------------------ 16 | 17 | # If your documentation needs a minimal Sphinx version, state it here. 18 | # needs_sphinx = '1.0' 19 | 20 | # Do not warn on external images. 21 | suppress_warnings = ["image.nonlocal_uri"] 22 | 23 | # Add any Sphinx extension module names here, as strings. They can be 24 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 25 | # ones. 26 | extensions = [ 27 | "sphinx.ext.autodoc", 28 | "sphinx.ext.coverage", 29 | "sphinx.ext.doctest", 30 | "sphinx.ext.intersphinx", 31 | "sphinx.ext.viewcode", 32 | "sphinx_click.ext", 33 | ] 34 | 35 | # Add any paths that contain templates here, relative to this directory. 36 | templates_path = ["_templates"] 37 | 38 | # The suffix(es) of source filenames. 39 | # You can specify multiple suffix as a list of string: 40 | # source_suffix = ['.rst', '.md'] 41 | source_suffix = ".rst" 42 | 43 | # The encoding of source files. 44 | # source_encoding = 'utf-8-sig' 45 | 46 | # The master toctree document. 47 | master_doc = "index" 48 | 49 | # General information about the project. 50 | project = "Flask-WebpackExt" 51 | copyright = "2017, CERN" 52 | author = "CERN" 53 | 54 | # The version info for the project you're documenting, acts as replacement for 55 | # |version| and |release|, also used in various other places throughout the 56 | # built documents. 57 | # 58 | # The short X.Y version. 59 | 60 | # The full version, including alpha/beta/rc tags. 61 | release = __version__ 62 | 63 | # The language for content autogenerated by Sphinx. Refer to documentation 64 | # for a list of supported languages. 65 | # 66 | # This is also used if you do content translation via gettext catalogs. 67 | # Usually you set "language" from the command line for these cases. 68 | language = "en" 69 | 70 | # There are two options for replacing |today|: either, you set today to some 71 | # non-false value, then it is used: 72 | # today = '' 73 | # Else, today_fmt is used as the format for a strftime call. 74 | # today_fmt = '%B %d, %Y' 75 | 76 | # List of patterns, relative to source directory, that match files and 77 | # directories to ignore when looking for source files. 78 | exclude_patterns = [] 79 | 80 | # The reST default role (used for this markup: `text`) to use for all 81 | # documents. 82 | # default_role = None 83 | 84 | # If true, '()' will be appended to :func: etc. cross-reference text. 85 | # add_function_parentheses = True 86 | 87 | # If true, the current module name will be prepended to all description 88 | # unit titles (such as .. function::). 89 | # add_module_names = True 90 | 91 | # If true, sectionauthor and moduleauthor directives will be shown in the 92 | # output. They are ignored by default. 93 | # show_authors = False 94 | 95 | # The name of the Pygments (syntax highlighting) style to use. 96 | pygments_style = "sphinx" 97 | 98 | # A list of ignored prefixes for module index sorting. 99 | # modindex_common_prefix = [] 100 | 101 | # If true, keep warnings as "system message" paragraphs in the built documents. 102 | # keep_warnings = False 103 | 104 | # If true, `todo` and `todoList` produce output, else they produce nothing. 105 | todo_include_todos = False 106 | 107 | 108 | # -- Options for HTML output ---------------------------------------------- 109 | html_theme = "alabaster" 110 | 111 | html_theme_options = { 112 | "description": "Webpack integration for Flask.", 113 | "github_user": "inveniosoftware", 114 | "github_repo": "flask-webpackext", 115 | "github_button": False, 116 | "github_banner": True, 117 | "show_powered_by": False, 118 | "extra_nav_links": { 119 | "flask-webpackext@GitHub": "https://github.com/inveniosoftware/flask-webpackext", 120 | "flask-webpackext@PyPI": "https://pypi.python.org/pypi/flask-webpackext/", 121 | }, 122 | } 123 | 124 | # The theme to use for HTML and HTML Help pages. See the documentation for 125 | # a list of builtin themes. 126 | 127 | # Theme options are theme-specific and customize the look and feel of a theme 128 | # further. For a list of options available for each theme, see the 129 | # documentation. 130 | # html_theme_options = {} 131 | 132 | # Add any paths that contain custom themes here, relative to this directory. 133 | # html_theme_path = [] 134 | 135 | # The name for this set of Sphinx documents. If None, it defaults to 136 | # " v documentation". 137 | # html_title = None 138 | 139 | # A shorter title for the navigation bar. Default is the same as html_title. 140 | # html_short_title = None 141 | 142 | # The name of an image file (relative to this directory) to place at the top 143 | # of the sidebar. 144 | # html_logo = None 145 | 146 | # The name of an image file (within the static path) to use as favicon of the 147 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 148 | # pixels large. 149 | # html_favicon = None 150 | 151 | # Add any paths that contain custom static files (such as style sheets) here, 152 | # relative to this directory. They are copied after the builtin static files, 153 | # so a file named "default.css" will overwrite the builtin "default.css". 154 | # html_static_path = ['_static'] 155 | 156 | # Add any extra paths that contain custom files (such as robots.txt or 157 | # .htaccess) here, relative to this directory. These files are copied 158 | # directly to the root of the documentation. 159 | # html_extra_path = [] 160 | 161 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 162 | # using the given strftime format. 163 | # html_last_updated_fmt = '%b %d, %Y' 164 | 165 | # If true, SmartyPants will be used to convert quotes and dashes to 166 | # typographically correct entities. 167 | # html_use_smartypants = True 168 | 169 | # Custom sidebar templates, maps document names to template names. 170 | html_sidebars = { 171 | "**": [ 172 | "about.html", 173 | "navigation.html", 174 | "relations.html", 175 | "searchbox.html", 176 | "donate.html", 177 | ] 178 | } 179 | 180 | # Additional templates that should be rendered to pages, maps page names to 181 | # template names. 182 | # html_additional_pages = {} 183 | 184 | # If false, no module index is generated. 185 | # html_domain_indices = True 186 | 187 | # If false, no index is generated. 188 | # html_use_index = True 189 | 190 | # If true, the index is split into individual pages for each letter. 191 | # html_split_index = False 192 | 193 | # If true, links to the reST sources are added to the pages. 194 | # html_show_sourcelink = True 195 | 196 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 197 | # html_show_sphinx = True 198 | 199 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 200 | # html_show_copyright = True 201 | 202 | # If true, an OpenSearch description file will be output, and all pages will 203 | # contain a tag referring to it. The value of this option must be the 204 | # base URL from which the finished HTML is served. 205 | # html_use_opensearch = '' 206 | 207 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 208 | # html_file_suffix = None 209 | 210 | # Language to be used for generating the HTML full-text search index. 211 | # Sphinx supports the following languages: 212 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' 213 | # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' 214 | # html_search_language = 'en' 215 | 216 | # A dictionary with options for the search language support, empty by default. 217 | # Now only 'ja' uses this config value 218 | # html_search_options = {'type': 'default'} 219 | 220 | # The name of a javascript file (relative to the configuration directory) that 221 | # implements a search results scorer. If empty, the default will be used. 222 | # html_search_scorer = 'scorer.js' 223 | 224 | # Output file base name for HTML help builder. 225 | htmlhelp_basename = "flask-webpackext_namedoc" 226 | 227 | # -- Options for LaTeX output --------------------------------------------- 228 | 229 | latex_elements = { 230 | # The paper size ('letterpaper' or 'a4paper'). 231 | #'papersize': 'letterpaper', 232 | # The font size ('10pt', '11pt' or '12pt'). 233 | #'pointsize': '10pt', 234 | # Additional stuff for the LaTeX preamble. 235 | #'preamble': '', 236 | # Latex figure (float) alignment 237 | #'figure_align': 'htbp', 238 | } 239 | 240 | # Grouping the document tree into LaTeX files. List of tuples 241 | # (source start file, target name, title, 242 | # author, documentclass [howto, manual, or own class]). 243 | latex_documents = [ 244 | ( 245 | master_doc, 246 | "flask-webpackext.tex", 247 | "flask-webpackext Documentation", 248 | "CERN", 249 | "manual", 250 | ), 251 | ] 252 | 253 | # The name of an image file (relative to this directory) to place at the top of 254 | # the title page. 255 | # latex_logo = None 256 | 257 | # For "manual" documents, if this is true, then toplevel headings are parts, 258 | # not chapters. 259 | # latex_use_parts = False 260 | 261 | # If true, show page references after internal links. 262 | # latex_show_pagerefs = False 263 | 264 | # If true, show URL addresses after external links. 265 | # latex_show_urls = False 266 | 267 | # Documents to append as an appendix to all manuals. 268 | # latex_appendices = [] 269 | 270 | # If false, no module index is generated. 271 | # latex_domain_indices = True 272 | 273 | 274 | # -- Options for manual page output --------------------------------------- 275 | 276 | # One entry per manual page. List of tuples 277 | # (source start file, name, description, authors, manual section). 278 | man_pages = [ 279 | (master_doc, "flask-webpackext", "flask-webpackext Documentation", [author], 1) 280 | ] 281 | 282 | # If true, show URL addresses after external links. 283 | # man_show_urls = False 284 | 285 | 286 | # -- Options for Texinfo output ------------------------------------------- 287 | 288 | # Grouping the document tree into Texinfo files. List of tuples 289 | # (source start file, target name, title, author, 290 | # dir menu entry, description, category) 291 | texinfo_documents = [ 292 | ( 293 | master_doc, 294 | "flask-webpackext", 295 | "Flask-WebpackExt Documentation", 296 | author, 297 | "flask-webpackext", 298 | "Webpack integration for Flask.", 299 | "Miscellaneous", 300 | ), 301 | ] 302 | 303 | # Documents to append as an appendix to all manuals. 304 | # texinfo_appendices = [] 305 | 306 | # If false, no module index is generated. 307 | # texinfo_domain_indices = True 308 | 309 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 310 | # texinfo_show_urls = 'footnote' 311 | 312 | # If true, do not generate a @detailmenu in the "Top" node's menu. 313 | # texinfo_no_detailmenu = False 314 | 315 | 316 | # Example configuration for intersphinx: refer to the Python standard library. 317 | intersphinx_mapping = { 318 | "python": ("https://docs.python.org/", None), 319 | "pywebpack": ("https://pywebpack.readthedocs.io/en/latest/", None), 320 | } 321 | 322 | # Autodoc configuraton. 323 | autoclass_content = "both" 324 | -------------------------------------------------------------------------------- /docs/configuration.rst: -------------------------------------------------------------------------------- 1 | Configuration 2 | ============= 3 | 4 | .. automodule:: flask_webpackext.config 5 | :members: 6 | -------------------------------------------------------------------------------- /docs/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CONTRIBUTING.rst 2 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst 2 | 3 | User's Guide 4 | ------------ 5 | 6 | This part of the documentation will show you how to get started in using 7 | Flask-WebpackExt. 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | 12 | installation 13 | configuration 14 | usage 15 | 16 | 17 | API Reference 18 | ------------- 19 | 20 | If you are looking for information on a specific function, class or method, 21 | this part of the documentation is for you. 22 | 23 | .. toctree:: 24 | :maxdepth: 2 25 | 26 | api 27 | 28 | Additional Notes 29 | ---------------- 30 | 31 | Notes on how to contribute, legal information and changes are here for the 32 | interested. 33 | 34 | .. toctree:: 35 | :maxdepth: 1 36 | 37 | contributing 38 | changes 39 | license 40 | authors 41 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../INSTALL.rst 2 | -------------------------------------------------------------------------------- /docs/license.rst: -------------------------------------------------------------------------------- 1 | License 2 | ======= 3 | 4 | .. include:: ../LICENSE 5 | 6 | .. note:: 7 | 8 | In applying this license, CERN does not waive the privileges and immunities 9 | granted to it by virtue of its status as an Intergovernmental Organization 10 | or submit itself to any jurisdiction. 11 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | echo. coverage to run coverage check of the documentation if enabled 41 | goto end 42 | ) 43 | 44 | if "%1" == "clean" ( 45 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 46 | del /q /s %BUILDDIR%\* 47 | goto end 48 | ) 49 | 50 | 51 | REM Check if sphinx-build is available and fallback to Python version if any 52 | %SPHINXBUILD% 2> nul 53 | if errorlevel 9009 goto sphinx_python 54 | goto sphinx_ok 55 | 56 | :sphinx_python 57 | 58 | set SPHINXBUILD=python -m sphinx.__init__ 59 | %SPHINXBUILD% 2> nul 60 | if errorlevel 9009 ( 61 | echo. 62 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 63 | echo.installed, then set the SPHINXBUILD environment variable to point 64 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 65 | echo.may add the Sphinx directory to PATH. 66 | echo. 67 | echo.If you don't have Sphinx installed, grab it from 68 | echo.http://sphinx-doc.org/ 69 | exit /b 1 70 | ) 71 | 72 | :sphinx_ok 73 | 74 | 75 | if "%1" == "html" ( 76 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 77 | if errorlevel 1 exit /b 1 78 | echo. 79 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 80 | goto end 81 | ) 82 | 83 | if "%1" == "dirhtml" ( 84 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 85 | if errorlevel 1 exit /b 1 86 | echo. 87 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 88 | goto end 89 | ) 90 | 91 | if "%1" == "singlehtml" ( 92 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 93 | if errorlevel 1 exit /b 1 94 | echo. 95 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 96 | goto end 97 | ) 98 | 99 | if "%1" == "pickle" ( 100 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 101 | if errorlevel 1 exit /b 1 102 | echo. 103 | echo.Build finished; now you can process the pickle files. 104 | goto end 105 | ) 106 | 107 | if "%1" == "json" ( 108 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 109 | if errorlevel 1 exit /b 1 110 | echo. 111 | echo.Build finished; now you can process the JSON files. 112 | goto end 113 | ) 114 | 115 | if "%1" == "htmlhelp" ( 116 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 117 | if errorlevel 1 exit /b 1 118 | echo. 119 | echo.Build finished; now you can run HTML Help Workshop with the ^ 120 | .hhp project file in %BUILDDIR%/htmlhelp. 121 | goto end 122 | ) 123 | 124 | if "%1" == "qthelp" ( 125 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 129 | .qhcp project file in %BUILDDIR%/qthelp, like this: 130 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Flask-WebpackExt.qhcp 131 | echo.To view the help file: 132 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Flask-WebpackExt.ghc 133 | goto end 134 | ) 135 | 136 | if "%1" == "devhelp" ( 137 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 138 | if errorlevel 1 exit /b 1 139 | echo. 140 | echo.Build finished. 141 | goto end 142 | ) 143 | 144 | if "%1" == "epub" ( 145 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 146 | if errorlevel 1 exit /b 1 147 | echo. 148 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 149 | goto end 150 | ) 151 | 152 | if "%1" == "latex" ( 153 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 154 | if errorlevel 1 exit /b 1 155 | echo. 156 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 157 | goto end 158 | ) 159 | 160 | if "%1" == "latexpdf" ( 161 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 162 | cd %BUILDDIR%/latex 163 | make all-pdf 164 | cd %~dp0 165 | echo. 166 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 167 | goto end 168 | ) 169 | 170 | if "%1" == "latexpdfja" ( 171 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 172 | cd %BUILDDIR%/latex 173 | make all-pdf-ja 174 | cd %~dp0 175 | echo. 176 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 177 | goto end 178 | ) 179 | 180 | if "%1" == "text" ( 181 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 182 | if errorlevel 1 exit /b 1 183 | echo. 184 | echo.Build finished. The text files are in %BUILDDIR%/text. 185 | goto end 186 | ) 187 | 188 | if "%1" == "man" ( 189 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 190 | if errorlevel 1 exit /b 1 191 | echo. 192 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 193 | goto end 194 | ) 195 | 196 | if "%1" == "texinfo" ( 197 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 198 | if errorlevel 1 exit /b 1 199 | echo. 200 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 201 | goto end 202 | ) 203 | 204 | if "%1" == "gettext" ( 205 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 206 | if errorlevel 1 exit /b 1 207 | echo. 208 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 209 | goto end 210 | ) 211 | 212 | if "%1" == "changes" ( 213 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 214 | if errorlevel 1 exit /b 1 215 | echo. 216 | echo.The overview file is in %BUILDDIR%/changes. 217 | goto end 218 | ) 219 | 220 | if "%1" == "linkcheck" ( 221 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 222 | if errorlevel 1 exit /b 1 223 | echo. 224 | echo.Link check complete; look for any errors in the above output ^ 225 | or in %BUILDDIR%/linkcheck/output.txt. 226 | goto end 227 | ) 228 | 229 | if "%1" == "doctest" ( 230 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 231 | if errorlevel 1 exit /b 1 232 | echo. 233 | echo.Testing of doctests in the sources finished, look at the ^ 234 | results in %BUILDDIR%/doctest/output.txt. 235 | goto end 236 | ) 237 | 238 | if "%1" == "coverage" ( 239 | %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage 240 | if errorlevel 1 exit /b 1 241 | echo. 242 | echo.Testing of coverage in the sources finished, look at the ^ 243 | results in %BUILDDIR%/coverage/python.txt. 244 | goto end 245 | ) 246 | 247 | if "%1" == "xml" ( 248 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 249 | if errorlevel 1 exit /b 1 250 | echo. 251 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 252 | goto end 253 | ) 254 | 255 | if "%1" == "pseudoxml" ( 256 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 257 | if errorlevel 1 exit /b 1 258 | echo. 259 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 260 | goto end 261 | ) 262 | 263 | :end 264 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | -e .[docs,tests] 2 | -------------------------------------------------------------------------------- /docs/usage.rst: -------------------------------------------------------------------------------- 1 | Usage 2 | ===== 3 | 4 | .. automodule:: flask_webpackext 5 | -------------------------------------------------------------------------------- /flask_webpackext/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017, 2018 CERN. 5 | # Copyright (C) 2024 Graz University of Technology. 6 | # 7 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 8 | # it under the terms of the Revised BSD License; see LICENSE file for 9 | # more details. 10 | 11 | r"""Webpack integration for Flask. 12 | 13 | A simple example 14 | ---------------- 15 | 16 | Let's create a basic Flask application inside ``app.py``. Jinja templates will 17 | reside in the ``templates`` folder and the static files, to be included in the 18 | template, in the ``instance/static`` folder: 19 | 20 | .. code-block:: python 21 | 22 | from flask import Flask 23 | 24 | app = Flask( 25 | __name__, 26 | template_folder='templates', 27 | static_folder='instance/static' 28 | ) 29 | 30 | Let's add a template and an asset to our project: 31 | 32 | .. code-block:: console 33 | 34 | src/ 35 | js/ 36 | main.js 37 | templates/ 38 | index.html 39 | app.py 40 | 41 | The asset will be a simple javascript file: 42 | 43 | .. code-block:: javascript 44 | 45 | import $ from 'jquery' 46 | 47 | $(document).ready(function(){ 48 | $("#msg").html("I am webpacked."); 49 | }); 50 | 51 | The content of the ``index.html`` we will define later. 52 | 53 | To build our asset, let's create the Webpack configuration in 54 | ``src/webpack.config.js``: 55 | 56 | .. code-block:: javascript 57 | 58 | var path = require('path'); 59 | var config = require('./config'); 60 | var ManifestPlugin = require('webpack-manifest-plugin'); 61 | 62 | module.exports = { 63 | context: config.build.context, 64 | entry: { 65 | app: "./js/main.js", 66 | }, 67 | output: { 68 | path: config.build.assetsPath, 69 | filename: 'js/[name].[chunkhash].js', 70 | publicPath: config.build.assetsURL 71 | }, 72 | plugins: [ 73 | new ManifestPlugin({ 74 | fileName: 'manifest.json', 75 | stripSrc: true, 76 | publicPath: config.build.assetsURL 77 | }) 78 | ] 79 | } 80 | 81 | You might have noticed that an import of a file which we did not create has 82 | been added, ``config.js``. This is because this file is generated by 83 | Flask-WebpackExt when we run the ``flask webpack create`` command and it will 84 | contain the following information:: 85 | 86 | { 87 | "build": { 88 | // Absolute path to the directory where Webpack outputs files 89 | // will be written to. 90 | "assetsPath": "/private/tmp/testproject/instance/static/dist", 91 | 92 | // URL to access the built assets. 93 | "assetsURL": "/static/dist/", 94 | 95 | // Absolute path to the generated assets directory. 96 | "context": "/private/tmp/testproject/instance/assets", 97 | 98 | // Boolean which represents if Flask debug is on. 99 | "debug": false, 100 | 101 | // Absolute path to the generated static directory. 102 | "staticPath": "/private/tmp/testproject/instance/static", 103 | 104 | // URL to access the static files. 105 | "staticURL": "/static/" 106 | } 107 | } 108 | 109 | 110 | This is really important since it is Flask, and only Flask, who knows where 111 | the application path for assets is, so through this configuration we tell 112 | Webpack where to move the bundles. 113 | 114 | Also, we will need a ``package.json`` for the npm dependencies, with a run 115 | script ``build`` that executes webpack, in ``src/package.json`` and will be 116 | triggered by ``flask webpack build``: 117 | 118 | .. code-block:: JSON 119 | 120 | { 121 | "private": true, 122 | "name": "example", 123 | "version": "0.0.1", 124 | "author": "myself", 125 | "license": "WTFPL", 126 | "description": "example", 127 | "scripts": { 128 | "build": "webpack --config webpack.config.js" 129 | }, 130 | "dependencies": { 131 | "jquery": "^3.2.1" 132 | }, 133 | "devDependencies": { 134 | "webpack-manifest-plugin": "^2.0.4" 135 | } 136 | } 137 | 138 | 139 | We can now define, in ``app.py`` a :class:`~project.WebpackTemplateProject` to 140 | integrate Webpack with our Flask application and build our assets: 141 | 142 | .. code-block:: python 143 | 144 | from flask_webpackext.project import WebpackTemplateProject 145 | from flask_webpackext import FlaskWebpackExt 146 | 147 | project = WebpackTemplateProject( 148 | __name__, 149 | project_folder='src', 150 | config_path='config.json', 151 | ) 152 | 153 | app.config.update(dict( 154 | WEBPACKEXT_PROJECT=project, 155 | )) 156 | 157 | # Initialize extension 158 | FlaskWebpackExt(app) 159 | 160 | Since Flask-WebpackExt creates a new template global function called 161 | ``webpack`` to inject the assets in templates, we can use it to include the 162 | assets in our template ``index.html``. 163 | 164 | .. code-block:: html 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 |
173 | {{ webpack['app.js'] }} 174 | 175 | 176 | 177 | Finally, we will expose our template through a Flask view: 178 | 179 | .. code-block:: python 180 | 181 | from flask import render_template 182 | 183 | @app.route('/') 184 | def index(): 185 | return render_template('index.html') 186 | 187 | At this point we are ready to build the assets: 188 | 189 | .. code-block:: console 190 | 191 | $ flask webpack buildall 192 | 193 | The command will copy all files from the `src` folder to the application 194 | instance folder designated for the Webpack project, download the npm packages 195 | and run Webpack to build our assets. 196 | 197 | Alternatively, we can execute each build step separately. To copy all sources 198 | to the working directory: 199 | 200 | .. code-block:: console 201 | 202 | $ flask webpack create 203 | 204 | To run `npm install` command and download all dependencies: 205 | 206 | .. code-block:: console 207 | 208 | $ flask webpack install 209 | 210 | To run `npm run build` and execute what you have defined in the 211 | `package.json`: 212 | 213 | .. code-block:: console 214 | 215 | $ flask webpack build 216 | 217 | Now you can run the application and see if the assets are loaded: 218 | 219 | .. code-block:: console 220 | 221 | $ export FLASK_APP=app.py 222 | $ flask run 223 | $ firefox http://127.0.0.1:5000/ 224 | 225 | Assets for multiple Flask modules 226 | --------------------------------- 227 | 228 | When working with large applications, assets are usually split in different 229 | modules. Flask-WebpackExt uses `pywebpack`_ which allows to solve this problem 230 | by using: 231 | 232 | - :class:`~bundle.WebpackBundle` to declare the needed assets and npm 233 | dependencies for each module. 234 | - :class:`~project.WebpackBundleProject` to gather all bundles under one 235 | Webpack project. 236 | 237 | An example project with two modules could be structured as follows: 238 | 239 | .. code-block:: console 240 | 241 | buildconfig/ 242 | package.json 243 | webpack.config.js 244 | modules/ 245 | module1/ 246 | js/ 247 | css/ 248 | module2/ 249 | js/ 250 | css/ 251 | templates/ 252 | index.html 253 | app.py 254 | 255 | Let's start with the definition of the first bundle ``bundle1``. ``bundle2`` 256 | would be similar: 257 | 258 | .. code-block:: python 259 | 260 | from flask_webpackext import WebpackBundle 261 | bundle1 = WebpackBundle( 262 | __name__, 263 | './modules/module1/static', 264 | entry={ 265 | 'module1-app': './js/module1-app.js', 266 | }, 267 | dependencies={ 268 | 'jquery': '^3.2.1' 269 | } 270 | ) 271 | 272 | We now define a :class:`~project.WebpackBundleProject` to put together all the 273 | bundles and integrate with Flask: 274 | 275 | .. code-block:: python 276 | 277 | from module1 import bundle1 278 | from module2 import bundle2 279 | from flask_webpackext import WebpackBundleProject 280 | 281 | myproject = WebpackBundleProject( 282 | __name__, 283 | project_folder='assets', 284 | config_path='src/config.json', 285 | bundles=[bundle1, bundle2], 286 | ) 287 | 288 | app.config.update(dict( 289 | WEBPACKEXT_PROJECT=myproject, 290 | )) 291 | 292 | # ... 293 | 294 | At this point, we can create the application and ``config.json`` will be 295 | generated. The main difference with the previous ``config.json`` is that 296 | Flask-WebpackExt now knows about the bundles, and it will add them under the 297 | key ``entry``:: 298 | 299 | { 300 | "build": {...}, 301 | "entry": { 302 | "module1": "./js/module1.js", 303 | "module2": "./js/module2.js" 304 | } 305 | } 306 | 307 | Because entries are now included in the ``config.json``, we can dynamically 308 | load them into ``webpack.config.js``:: 309 | 310 | var config = require('./config') 311 | 312 | module.exports = { 313 | context: config.build.context, 314 | entry: config.entry, 315 | ... 316 | }; 317 | 318 | 319 | Manifest 320 | -------- 321 | 322 | Flask-WebpackExt can load the ``manifest.json`` created by webpack when 323 | building the assets. You have to add the plugin in the ``webpack.config.js`` 324 | to generate it:: 325 | 326 | ... 327 | var ManifestPlugin = require('webpack-manifest-plugin'); 328 | 329 | module.exports = { 330 | ... 331 | plugins: [ 332 | new ManifestPlugin({ 333 | fileName: 'manifest.json', 334 | stripSrc: true, 335 | publicPath: config.build.assetsURL 336 | }) 337 | ] 338 | }; 339 | 340 | The generated ``manifest.json`` will look like : 341 | 342 | .. code-block:: javascript 343 | 344 | { 345 | "module1.js": "/static/dist/js/module1.4adb22699eb1a5698794.js", 346 | "module2.js": "/static/dist/js/module2.85e58794420201dc1426.js" 347 | } 348 | 349 | By default, Flask-WebpackExt will look for the manifest file in 350 | `WEBPACKEXT_MANIFEST_PATH` config variable, and if it exists, it will load the 351 | file and make it available inside Jinja templates. 352 | 353 | The injected asset in the generated html template will look similar to this:: 354 | 355 | 356 | 357 | You can read more about it on `pywebpack`_ documentation. 358 | 359 | .. _pywebpack: https://pywebpack.readthedocs.io 360 | """ 361 | 362 | from pywebpack import WebpackProject 363 | 364 | from .bundle import WebpackBundle 365 | from .ext import FlaskWebpackExt 366 | from .project import WebpackBundleProject, WebpackTemplateProject 367 | from .proxies import current_manifest, current_webpack 368 | 369 | __version__ = "2.1.0" 370 | 371 | __all__ = ( 372 | "__version__", 373 | "current_manifest", 374 | "current_webpack", 375 | "FlaskWebpackExt", 376 | "WebpackBundle", 377 | "WebpackBundleProject", 378 | "WebpackProject", 379 | "WebpackTemplateProject", 380 | ) 381 | -------------------------------------------------------------------------------- /flask_webpackext/bundle.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2018 CERN. 5 | # Copyright (C) 2024 Graz University of Technology. 6 | # 7 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 8 | # it under the terms of the Revised BSD License; see LICENSE file for 9 | # more details. 10 | 11 | """Webpack bundle APIs for Flask-WebpackExt.""" 12 | 13 | from os.path import join 14 | 15 | from flask.helpers import get_root_path 16 | from pywebpack import WebpackBundle as PyWebpackBundle 17 | 18 | 19 | class WebpackBundle(PyWebpackBundle): 20 | """Flask webpack bundle.""" 21 | 22 | def __init__(self, import_name, folder, **kwargs): 23 | """Initialize bundle. 24 | 25 | :param import_name: Name of the module where the WebpackBundle class 26 | is instantiated. It is used to determine the absolute path to the 27 | ``folder`` where the assets are located. 28 | :param folder: Relative path to the assets. 29 | :param kwargs: Keyword arguments directly passed to 30 | :class:`pywebpack.bundle.WebpackBundle`. 31 | """ 32 | super().__init__(join(get_root_path(import_name), folder), **kwargs) 33 | -------------------------------------------------------------------------------- /flask_webpackext/cli.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017, 2018 CERN. 5 | # Copyright (C) 2024 Graz University of Technology. 6 | # 7 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 8 | # it under the terms of the Revised BSD License; see LICENSE file for 9 | # more details. 10 | 11 | """CLI for Flask-WebpackExt.""" 12 | 13 | import click 14 | from flask.cli import with_appcontext 15 | 16 | from .proxies import current_webpack 17 | 18 | 19 | def _run(cmd, unavailable_msg, success_msg): 20 | project = current_webpack.project 21 | if not hasattr(project, cmd): 22 | click.secho(unavailable_msg, fg="yellow") 23 | else: 24 | getattr(current_webpack.project, cmd)() 25 | click.secho(success_msg, fg="green") 26 | 27 | 28 | @click.group(chain=True) 29 | @with_appcontext 30 | def webpack(): 31 | """Webpack commands.""" 32 | 33 | 34 | @webpack.command() 35 | @with_appcontext 36 | def create(): 37 | """Create webpack project. This will fetch the assets.""" 38 | _run("create", "Nothing to do for project.", "Created webpack project.") 39 | 40 | 41 | @webpack.command() 42 | @with_appcontext 43 | def clean(): 44 | """Remove created webpack project.""" 45 | _run("clean", "Nothing to do for project.", "Cleaned webpack project.") 46 | 47 | 48 | @webpack.command(context_settings={"ignore_unknown_options": True}) 49 | @click.argument("args", nargs=-1, type=click.UNPROCESSED) 50 | @with_appcontext 51 | def install(args): 52 | """Run NPM install.""" 53 | current_webpack.project.install(*args) 54 | click.secho("Installed webpack project.", fg="green") 55 | 56 | 57 | @webpack.command(context_settings={"ignore_unknown_options": True}) 58 | @click.argument("args", nargs=-1, type=click.UNPROCESSED) 59 | @with_appcontext 60 | def build(args): 61 | """Run NPM build-script.""" 62 | current_webpack.project.build(*args) 63 | click.secho("Built webpack project.", fg="green") 64 | 65 | 66 | @webpack.command() 67 | @with_appcontext 68 | def buildall(): 69 | """Create, install and build webpack project.""" 70 | current_webpack.project.buildall() 71 | click.secho("Created, installed and built webpack project.", fg="green") 72 | 73 | 74 | @webpack.command(context_settings={"ignore_unknown_options": True}) 75 | @click.argument("script") 76 | @click.argument("args", nargs=-1, type=click.UNPROCESSED) 77 | @with_appcontext 78 | def run(script, args): 79 | """Run an NPM script.""" 80 | try: 81 | current_webpack.project.run(script, *args) 82 | click.secho('Executed NPM script "{}".'.format(script), fg="green") 83 | except RuntimeError: 84 | raise click.BadParameter('"{}" is not a valid NPM script.'.format(script)) 85 | -------------------------------------------------------------------------------- /flask_webpackext/config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017, 2018 CERN. 5 | # Copyright (C) 2024 Graz University of Technology. 6 | # 7 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 8 | # it under the terms of the Revised BSD License; see LICENSE file for 9 | # more details. 10 | 11 | """Webpack integration for Flask.""" 12 | 13 | WEBPACKEXT_MANIFEST_LOADER = None 14 | """Manifest loader use to load manifest. By default ``JinjaManifestLoader``. 15 | """ 16 | 17 | WEBPACKEXT_MANIFEST_PATH = "dist/manifest.json" 18 | """Path to manifest file relative to static folder.""" 19 | 20 | WEBPACKEXT_PROJECT = None 21 | """Webpack project.""" 22 | 23 | WEBPACKEXT_PROJECT_BUILDDIR = None 24 | """Directory where Webpack project should be copied to prior to build. By 25 | default ``assets``. 26 | """ 27 | 28 | WEBPACKEXT_PROJECT_DISTDIR = None 29 | """Directory where Webpack output files should be written to. By default 30 | ``dist``. 31 | """ 32 | 33 | WEBPACKEXT_PROJECT_DISTURL = None 34 | """URL path to where Webpack output files are accessible. By default ``dist``. 35 | """ 36 | 37 | WEBPACKEXT_STORAGE_CLS = None 38 | """Default storage class. By default ``FileStorage``. 39 | """ 40 | -------------------------------------------------------------------------------- /flask_webpackext/errors.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017 CERN. 5 | # 6 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 7 | # it under the terms of the Revised BSD License; see LICENSE file for 8 | # more details. 9 | 10 | """Errors.""" 11 | 12 | 13 | class ManifestKeyNotFoundError(Exception): 14 | """Manifest key not found.""" 15 | -------------------------------------------------------------------------------- /flask_webpackext/ext.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017 CERN. 5 | # Copyright (C) 2024 Graz University of Technology. 6 | # 7 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 8 | # it under the terms of the Revised BSD License; see LICENSE file for 9 | # more details. 10 | 11 | """Webpack integration for Flask.""" 12 | 13 | from os.path import join 14 | 15 | from pynpm.package import NPMPackage 16 | from pywebpack import FileStorage 17 | from werkzeug.utils import import_string 18 | 19 | from . import config 20 | from .manifest import JinjaManifestLoader 21 | from .proxies import current_manifest 22 | 23 | 24 | class FlaskWebpackExt(object): 25 | """Flask-WebpackExt extension.""" 26 | 27 | def __init__(self, app=None): 28 | """Extension initialization.""" 29 | if app: 30 | self.init_app(app) 31 | 32 | def init_app(self, app): 33 | """Flask application initialization.""" 34 | self.init_config(app) 35 | app.add_template_global(current_manifest, name="webpack") 36 | app.extensions["flask-webpackext"] = _FlaskWebpackExtState(app) 37 | 38 | def init_config(self, app): 39 | """Initialize configuration.""" 40 | app.config.setdefault( 41 | "WEBPACKEXT_PROJECT_DISTDIR", 42 | join(app.static_folder, "dist"), 43 | ) 44 | app.config.setdefault( 45 | "WEBPACKEXT_PROJECT_DISTURL", 46 | join(app.static_url_path, "dist"), 47 | ) 48 | app.config.setdefault( 49 | "WEBPACKEXT_PROJECT_BUILDDIR", 50 | join(app.instance_path, "assets"), 51 | ) 52 | app.config.setdefault("WEBPACKEXT_STORAGE_CLS", FileStorage) 53 | app.config.setdefault( 54 | "WEBPACKEXT_MANIFEST_LOADER", 55 | JinjaManifestLoader, 56 | ) 57 | app.config.setdefault( 58 | "WEBPACKEXT_NPM_PKG_CLS", 59 | NPMPackage, 60 | ) 61 | 62 | for k in dir(config): 63 | if k.startswith("WEBPACKEXT_"): 64 | app.config.setdefault(k, getattr(config, k)) 65 | 66 | 67 | class _FlaskWebpackExtState(object): 68 | """Flask webpack state object.""" 69 | 70 | def __init__(self, app): 71 | """Initialize state.""" 72 | self.app = app 73 | 74 | @property 75 | def manifest_loader(self): 76 | """Manifest loader.""" 77 | loader = self.app.config["WEBPACKEXT_MANIFEST_LOADER"] 78 | if isinstance(loader, str): 79 | return import_string(loader) 80 | return loader 81 | 82 | @property 83 | def manifest(self): 84 | """Manifest.""" 85 | path = self.app.config["WEBPACKEXT_MANIFEST_PATH"] 86 | if path: 87 | return self.manifest_loader().load(join(self.app.static_folder, path)) 88 | return None 89 | 90 | @property 91 | def project(self): 92 | """Webpack project.""" 93 | project = self.app.config["WEBPACKEXT_PROJECT"] 94 | if isinstance(project, str): 95 | return import_string(project) 96 | return project 97 | 98 | @property 99 | def storage_cls(self): 100 | """Default storage class.""" 101 | cls_ = self.app.config["WEBPACKEXT_STORAGE_CLS"] 102 | if isinstance(cls_, str): 103 | return import_string(cls_) 104 | return cls_ 105 | 106 | @property 107 | def npm_pkg_cls(self): 108 | """Default JS package manager class.""" 109 | cls_ = self.app.config["WEBPACKEXT_NPM_PKG_CLS"] 110 | if isinstance(cls_, str): 111 | return import_string(cls_) 112 | return cls_ 113 | -------------------------------------------------------------------------------- /flask_webpackext/manifest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017 CERN. 5 | # Copyright (C) 2024 Graz University of Technology. 6 | # 7 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 8 | # it under the terms of the Revised BSD License; see LICENSE file for 9 | # more details. 10 | 11 | """Proxy to current extension.""" 12 | 13 | 14 | from flask import current_app 15 | from markupsafe import Markup 16 | from pywebpack import Manifest, ManifestEntry, ManifestLoader 17 | 18 | from .errors import ManifestKeyNotFoundError 19 | 20 | 21 | class JinjaManifest(Manifest): 22 | """Manifest entry which marks rendered strings as safe for Jinja.""" 23 | 24 | def __getitem__(self, key): 25 | """Get a manifest entry.""" 26 | try: 27 | return super().__getitem__(key) 28 | except KeyError: 29 | raise ManifestKeyNotFoundError( 30 | "Key {} not found in manifest.json".format(key) 31 | ) 32 | 33 | def __getattr__(self, name): 34 | """Get a manifest entry.""" 35 | try: 36 | return super().__getattr__(name) 37 | except AttributeError: 38 | msg = f"Key {name} not found in manifest.json" 39 | raise ManifestKeyNotFoundError(msg) 40 | 41 | 42 | class JinjaManifestEntry(ManifestEntry): 43 | """Manifest entry which marks rendered strings as safe for Jinja.""" 44 | 45 | def __html__(self): 46 | """Ensures that string is not escaped when included in Jinja.""" 47 | return Markup(self.render()) 48 | 49 | 50 | class JinjaManifestLoader(ManifestLoader): 51 | """Factory which uses the Jinja manifest entry.""" 52 | 53 | cache = {} 54 | 55 | def __init__(self, manifest_cls=JinjaManifest, entry_cls=JinjaManifestEntry): 56 | """Initialize manifest loader.""" 57 | super().__init__(manifest_cls=manifest_cls, entry_cls=entry_cls) 58 | 59 | def load(self, filepath): 60 | """Load a manifest from a file.""" 61 | if current_app.debug or filepath not in JinjaManifestLoader.cache: 62 | JinjaManifestLoader.cache[filepath] = super().load(filepath) 63 | return JinjaManifestLoader.cache[filepath] 64 | -------------------------------------------------------------------------------- /flask_webpackext/project.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017, 2018 CERN. 5 | # Copyright (C) 2024 Graz University of Technology. 6 | # 7 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 8 | # it under the terms of the Revised BSD License; see LICENSE file for 9 | # more details. 10 | 11 | """Webpack project utilities for Flask-WebpackExt.""" 12 | 13 | from os.path import join 14 | 15 | from flask import current_app 16 | from flask.helpers import get_root_path 17 | from pywebpack import WebpackBundleProject as PyWebpackBundleProject 18 | from pywebpack import WebpackTemplateProject as PyWebpackTemplateProject 19 | from pywebpack.helpers import cached 20 | 21 | from .proxies import current_webpack 22 | 23 | 24 | def flask_config(): 25 | """Flask configuration injected in Webpack. 26 | 27 | :return: Dictionary which contains the information Flask-WebpackExt knows 28 | about a Webpack project and the absolute URLs for static files and 29 | assets. The dictionary consists of a key ``build`` with the following 30 | keys inside: 31 | 32 | * ``debug``: Boolean which represents if Flask debug is on. 33 | * ``context``: Absolute path to the generated assets directory. 34 | * ``assetsPath``: Absolute path to the generated static directory. 35 | * ``assetsURL``: URL to access the built files. 36 | * ``staticPath``: Absolute path to the generated static directory. 37 | * ``staticURL``: URL to access the static files.. 38 | """ 39 | assets_url = current_app.config["WEBPACKEXT_PROJECT_DISTURL"] 40 | if not assets_url.endswith("/"): 41 | assets_url += "/" 42 | static_url = current_app.static_url_path 43 | if not static_url.endswith("/"): 44 | static_url += "/" 45 | 46 | return { 47 | "build": { 48 | "debug": current_app.debug, 49 | "context": current_webpack.project.path, 50 | "assetsPath": current_app.config["WEBPACKEXT_PROJECT_DISTDIR"], 51 | "assetsURL": assets_url, 52 | "staticPath": current_app.static_folder, 53 | "staticURL": static_url, 54 | } 55 | } 56 | 57 | 58 | def flask_allowed_copy_paths(): 59 | """Get the allowed copy paths from the Flask application.""" 60 | return [ 61 | current_app.instance_path, 62 | current_webpack.project.path, 63 | current_app.static_folder, 64 | current_app.config["WEBPACKEXT_PROJECT_DISTDIR"], 65 | ] 66 | 67 | 68 | class _PathStoragePackageMixin: 69 | """Mixin class for overriding various properties of the base ``WebpackProject``.""" 70 | 71 | @property 72 | def path(self): 73 | """Get path to project.""" 74 | return current_app.config["WEBPACKEXT_PROJECT_BUILDDIR"] 75 | 76 | @property 77 | def storage_cls(self): 78 | """Get storage class.""" 79 | return current_webpack.storage_cls 80 | 81 | @property 82 | @cached 83 | def npmpkg(self): 84 | """Get API to the package for the configured package manager.""" 85 | npm_pkg_cls = current_webpack.npm_pkg_cls 86 | return npm_pkg_cls(self.path) 87 | 88 | 89 | class WebpackTemplateProject(_PathStoragePackageMixin, PyWebpackTemplateProject): 90 | """Flask webpack template project.""" 91 | 92 | def __init__( 93 | self, import_name, project_folder=None, config=None, config_path=None, **kwargs 94 | ): 95 | """Initialize project. 96 | 97 | :param import_name: Name of the module where the 98 | WebpackTemplateProject class is instantiated. It is used to 99 | determine the absolute path to the ``project_folder``. 100 | :param project_folder: Relative path to the Webpack project. 101 | :param config: Dictionary which overrides the ``config.json`` file 102 | generated by Flask-WebpackExt. Use carefuly and only if you know 103 | what you are doing since ``config.json`` is the file that holds the 104 | key information to integrate Flask with Webpack. 105 | :param config_path: Path where Flask-WebpackExt is going to write the 106 | ``config.json``, this file is generated by 107 | :func:`flask_webpackext.project.flask_config`. 108 | :param kwargs: Keyword arguments to be passed to the super constructor. 109 | """ 110 | project_template_dir = join(get_root_path(import_name), project_folder) 111 | super().__init__( 112 | None, 113 | project_template_dir=project_template_dir, 114 | config=config or flask_config, 115 | config_path=config_path, 116 | **kwargs, 117 | ) 118 | 119 | 120 | class WebpackBundleProject(_PathStoragePackageMixin, PyWebpackBundleProject): 121 | """Flask webpack bundle project.""" 122 | 123 | def __init__( 124 | self, 125 | import_name, 126 | project_folder=None, 127 | bundles=None, 128 | config=None, 129 | config_path=None, 130 | allowed_copy_paths=None, 131 | **kwargs, 132 | ): 133 | """Initialize templated folder. 134 | 135 | :param import_name: Name of the module where the WebpackBundleProject 136 | class is instantiated. It is used to determine the absolute path 137 | to the ``project_folder``. 138 | :param project_folder: Relative path to the Webpack project which is 139 | going to aggregate all the ``bundles``. 140 | :param bundles: List of 141 | :class:`flask_webpackext.bundle.WebpackBundle`. This list can be 142 | statically defined if the bundles are known before hand, or 143 | dinamically generated using 144 | :func:`pywebpack.helpers.bundles_from_entry_point` so the bundles 145 | are discovered from the defined Webpack entrypoints exposed by 146 | other modules. 147 | :param config: Dictionary which overrides the ``config.json`` file 148 | generated by Flask-WebpackExt. Use carefuly and only if you know 149 | what you are doing since ``config.json`` is the file that holds the 150 | key information to integrate Flask with Webpack. 151 | :param config_path: Path where Flask-WebpackExt is going to write the 152 | ``config.json``, this file is generated by 153 | :func:`flask_webpackext.project.flask_config`. 154 | :param allowed_copy_paths: List of paths (absolute, or relative to 155 | the `config_path`) that are allowed for bundle copy instructions. 156 | :param kwargs: Keyword arguments to be passed to the super constructor. 157 | """ 158 | project_template_dir = join(get_root_path(import_name), project_folder) 159 | super().__init__( 160 | None, 161 | project_template_dir=project_template_dir, 162 | bundles=bundles, 163 | config=config or flask_config, 164 | config_path=config_path, 165 | allowed_copy_paths=allowed_copy_paths or flask_allowed_copy_paths, 166 | **kwargs, 167 | ) 168 | -------------------------------------------------------------------------------- /flask_webpackext/proxies.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017 CERN. 5 | # Copyright (C) 2024 Graz University of Technology. 6 | # 7 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 8 | # it under the terms of the Revised BSD License; see LICENSE file for 9 | # more details. 10 | 11 | """Proxy to current extension.""" 12 | 13 | from flask import current_app 14 | from werkzeug.local import LocalProxy 15 | 16 | current_webpack = LocalProxy(lambda: current_app.extensions["flask-webpackext"]) 17 | """Proxy to current extension.""" 18 | 19 | current_manifest = LocalProxy(lambda: current_webpack.manifest) 20 | """Proxy to current manifest.""" 21 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools", "wheel", "babel>2.8"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | -------------------------------------------------------------------------------- /requirements-devel.txt: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017 CERN. 5 | # 6 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 7 | # it under the terms of the Revised BSD License; see LICENSE file for 8 | # more details. 9 | 10 | -e git+git://github.com/inveniosoftware/pynpm.git#egg=pynpm 11 | -e git+git://github.com/inveniosoftware/pywebpack.git#egg=pywebpack 12 | -------------------------------------------------------------------------------- /run-tests.sh: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017 CERN. 5 | # Copyright (C) 2024 Graz University of Technology. 6 | # 7 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 8 | # it under the terms of the Revised BSD License; see LICENSE file for 9 | # more details. 10 | 11 | # Quit on errors 12 | set -o errexit 13 | 14 | # Quit on unbound symbols 15 | set -o nounset 16 | 17 | python -m check_manifest 18 | python -m sphinx.cmd.build -qnNW docs docs/_build/html 19 | python -m pytest 20 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017 CERN. 5 | # Copyright (C) 2024 Graz University of Technology. 6 | # 7 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 8 | # it under the terms of the Revised BSD License; see LICENSE file for 9 | # more details. 10 | 11 | [metadata] 12 | name = flask-webpackext 13 | version = attr: flask_webpackext.__version__ 14 | description = Webpack integration for Flask. 15 | long_description = file: README.rst, CHANGES.rst 16 | keywords = flask webpack 17 | license = BSD 18 | author = CERN 19 | author_email = info@inveniosoftware.org 20 | platforms = any 21 | url = https://github.com/inveniosoftware/flask-webpackext 22 | classifiers = 23 | Development Status :: 5 - Production/Stable 24 | 25 | [options] 26 | include_package_data = True 27 | packages = find: 28 | python_requires = >=3.7 29 | zip_safe = False 30 | install_requires = 31 | Flask>=0.11 32 | pywebpack>=2.1.0,<3.0.0 33 | 34 | [options.extras_require] 35 | tests = 36 | pytest-black-ng>=0.4.0 37 | check-manifest>=0.25 38 | coverage>=4.0 39 | isort>=4.3.21 40 | pydocstyle>=1.0.0 41 | pytest-cache>=1.0 42 | pytest-cov>=1.8.0 43 | pytest>=2.8.0 44 | sphinx>=4.5 45 | sphinx-click>=1.4.0 46 | # Kept for backwards compatibility 47 | docs = 48 | 49 | [options.entry_points] 50 | flask.commands = 51 | webpack = flask_webpackext.cli:webpack 52 | 53 | [build_sphinx] 54 | source-dir = docs/ 55 | build-dir = docs/_build 56 | all_files = 1 57 | 58 | [bdist_wheel] 59 | universal = 1 60 | 61 | [pydocstyle] 62 | add_ignore = D401 63 | 64 | [isort] 65 | profile=black 66 | 67 | [check-manifest] 68 | ignore = 69 | *-requirements.txt 70 | 71 | [tool:pytest] 72 | addopts = --black --doctest-glob="*.rst" --doctest-modules --cov=flask_webpackext --cov-report=term-missing docs tests flask_webpackext 73 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017 CERN. 5 | # Copyright (C) 2024 Graz University of Technology. 6 | # 7 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 8 | # it under the terms of the Revised BSD License; see LICENSE file for 9 | # more details. 10 | 11 | """Webpack integration for Flask.""" 12 | 13 | from setuptools import setup 14 | 15 | setup() 16 | -------------------------------------------------------------------------------- /tests/assets/index.js: -------------------------------------------------------------------------------- 1 | console.log('index') 2 | -------------------------------------------------------------------------------- /tests/assets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "simple", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "build": "webpack --config webpack.config.js" 7 | }, 8 | "keywords": [], 9 | "author": "", 10 | "license": "ISC", 11 | "description": "", 12 | "dependencies": { 13 | "jquery": "^3.2.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/assets/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | module.exports = { 4 | entry: './index.js', 5 | context: path.resolve(__dirname), 6 | output: { 7 | filename: 'bundle.js', 8 | path: path.resolve(__dirname, 'build'), 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /tests/assetsbundle/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "simple", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "build": "webpack --config webpack.config.js" 7 | }, 8 | "keywords": [], 9 | "author": "", 10 | "license": "ISC", 11 | "description": "" 12 | } 13 | -------------------------------------------------------------------------------- /tests/assetsbundle/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var config = require('./config.json') 3 | 4 | module.exports = { 5 | entry: config.entry, 6 | context: config.build.context, 7 | output: { 8 | filename: '[name].js', 9 | path: config.build.assetsPath, 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /tests/bundle1/app1.js: -------------------------------------------------------------------------------- 1 | console.log('app1') 2 | -------------------------------------------------------------------------------- /tests/bundle2/app2.js: -------------------------------------------------------------------------------- 1 | console.log('app2') 2 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017 CERN. 5 | # 6 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 7 | # it under the terms of the Revised BSD License; see LICENSE file for 8 | # more details. 9 | 10 | """Pytest configuration.""" 11 | 12 | import shutil 13 | import tempfile 14 | from os import makedirs 15 | from os.path import dirname, join 16 | 17 | import pytest 18 | from click.testing import CliRunner 19 | from flask import Flask 20 | from flask.cli import ScriptInfo 21 | 22 | from flask_webpackext import ( 23 | FlaskWebpackExt, 24 | WebpackBundle, 25 | WebpackBundleProject, 26 | WebpackProject, 27 | WebpackTemplateProject, 28 | ) 29 | 30 | 31 | @pytest.fixture() 32 | def tmpdir(): 33 | """Temporary directory.""" 34 | path = tempfile.mkdtemp() 35 | yield path 36 | shutil.rmtree(path) 37 | 38 | 39 | @pytest.fixture() 40 | def instance_path(tmpdir): 41 | """Temporary instance path.""" 42 | f = join(tmpdir, "instance") 43 | makedirs(f) 44 | return f 45 | 46 | 47 | @pytest.fixture() 48 | def static_folder(instance_path): 49 | """Static folder.""" 50 | f = join(instance_path, "static") 51 | makedirs(f) 52 | return f 53 | 54 | 55 | @pytest.fixture() 56 | def manifest(static_folder): 57 | """Static folder.""" 58 | src = join(dirname(__file__), "manifest.json") 59 | dst = join(static_folder, "dist/manifest.json") 60 | makedirs(dirname(dst)) 61 | shutil.copyfile(src, dst) 62 | return dst 63 | 64 | 65 | @pytest.fixture() 66 | def app(instance_path, static_folder): 67 | """Flask application.""" 68 | app_ = Flask("test", instance_path=instance_path, static_folder=static_folder) 69 | FlaskWebpackExt(app_) 70 | return app_ 71 | 72 | 73 | @pytest.fixture() 74 | def appctx(app): 75 | """App in application context.""" 76 | with app.app_context(): 77 | yield app 78 | 79 | 80 | @pytest.fixture() 81 | def ext(app): 82 | """Extension instance.""" 83 | return app.extensions["flask-webpackext"] 84 | 85 | 86 | @pytest.fixture() 87 | def project_assets_dir(tmpdir): 88 | """Temporary project assets dir.""" 89 | src = join(dirname(__file__), "assets") 90 | dst = join(tmpdir, "project") 91 | shutil.copytree(src, dst) 92 | return dst 93 | 94 | 95 | @pytest.fixture() 96 | def project(app, project_assets_dir): 97 | """Webpack project.""" 98 | project = WebpackProject(project_assets_dir) 99 | app.config.update( 100 | { 101 | "WEBPACKEXT_PROJECT": project, 102 | } 103 | ) 104 | return project 105 | 106 | 107 | @pytest.fixture() 108 | def projecttpl(app): 109 | """Webpack project.""" 110 | project = WebpackTemplateProject(__name__, "assets") 111 | app.config.update( 112 | { 113 | "WEBPACKEXT_PROJECT": project, 114 | } 115 | ) 116 | return project 117 | 118 | 119 | @pytest.fixture() 120 | def bundles(): 121 | """Webpack bundles.""" 122 | return ( 123 | WebpackBundle(__name__, "bundle1", entry={"app1": "./app1.js"}), 124 | WebpackBundle(__name__, "bundle2", entry={"app2": "./app2.js"}), 125 | ) 126 | 127 | 128 | @pytest.fixture() 129 | def projectbundle(app, bundles): 130 | """Webpack bundle project.""" 131 | project = WebpackBundleProject(__name__, "assetsbundle", bundles=bundles) 132 | app.config.update( 133 | { 134 | "WEBPACKEXT_PROJECT": project, 135 | } 136 | ) 137 | return project 138 | 139 | 140 | @pytest.fixture() 141 | def cli_obj(app): 142 | """Script info.""" 143 | return ScriptInfo(create_app=lambda: app) 144 | 145 | 146 | @pytest.fixture() 147 | def runner(): 148 | """CLI Runner.""" 149 | return CliRunner() 150 | -------------------------------------------------------------------------------- /tests/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "/static/dist/app.js" 3 | } 4 | -------------------------------------------------------------------------------- /tests/test_cli.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017 CERN. 5 | # Copyright (C) 2025 Graz University of Technology. 6 | # 7 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 8 | # it under the terms of the Revised BSD License; see LICENSE file for 9 | # more details. 10 | 11 | """Module tests.""" 12 | 13 | import importlib.metadata 14 | from os.path import exists, join 15 | 16 | import pytest 17 | from click.testing import CliRunner 18 | 19 | from flask_webpackext.cli import webpack 20 | 21 | 22 | def test_webpack(project): 23 | """Test webpack command.""" 24 | runner = CliRunner() 25 | result = runner.invoke(webpack) 26 | if importlib.metadata.version("click") < "8.2.0": 27 | # click >= 8.2.0 dropped python3.9 support 28 | assert result.exit_code == 0 29 | else: 30 | assert result.exit_code == 2 31 | 32 | 33 | @pytest.mark.parametrize("cmd", ["create", "clean"]) 34 | def test_simple_create_clean(cmd, runner, project, cli_obj): 35 | """Test create/clean command on simple project.""" 36 | result = runner.invoke(webpack, [cmd], obj=cli_obj) 37 | assert result.exit_code == 0 38 | assert "Nothing to do" in result.output 39 | 40 | 41 | def test_simple_chain(runner, project, cli_obj): 42 | """Test chaining commands.""" 43 | result = runner.invoke( 44 | webpack, 45 | [ 46 | "create", 47 | "clean", 48 | ], 49 | obj=cli_obj, 50 | ) 51 | assert result.exit_code == 0 52 | assert "Nothing to do" in result.output 53 | 54 | 55 | def test_simple_install(project, project_assets_dir, runner, cli_obj): 56 | """Test install command on simple project.""" 57 | node_dir = join(project_assets_dir, "node_modules") 58 | assert not exists(node_dir) 59 | result = runner.invoke(webpack, ["install"], obj=cli_obj) 60 | assert result.exit_code == 0 61 | assert "Installed webpack project." in result.output 62 | assert exists(node_dir) 63 | 64 | # Test args passing 65 | result = runner.invoke(webpack, ["install", "--report"], obj=cli_obj) 66 | assert result.exit_code == 0 67 | 68 | 69 | def test_simple_build(project, project_assets_dir, runner, cli_obj): 70 | """Test build comand on simple project.""" 71 | bundle_js = join(project_assets_dir, "build/bundle.js") 72 | assert not exists(bundle_js) 73 | result = runner.invoke(webpack, ["build"], obj=cli_obj) 74 | assert result.exit_code == 0 75 | assert "Built webpack project." in result.output 76 | assert exists(bundle_js) 77 | 78 | 79 | def test_simple_run(project, project_assets_dir, runner, cli_obj): 80 | """Test run command.""" 81 | bundle_js = join(project_assets_dir, "build/bundle.js") 82 | assert not exists(bundle_js) 83 | result = runner.invoke(webpack, ["run", "build"], obj=cli_obj) 84 | assert result.exit_code == 0 85 | assert 'Executed NPM script "build"' in result.output 86 | assert exists(bundle_js) 87 | 88 | 89 | def test_simple_run_error(project, project_assets_dir, runner, cli_obj): 90 | """Test run command with invalid script.""" 91 | result = runner.invoke(webpack, ["run", "invalid"], obj=cli_obj) 92 | assert result.exit_code != 0 93 | 94 | 95 | def test_simple_buildall(project, project_assets_dir, runner, cli_obj): 96 | """Test buildall command on simple project.""" 97 | bundle_js = join(project_assets_dir, "build/bundle.js") 98 | node_dir = join(project_assets_dir, "node_modules") 99 | assert not exists(bundle_js) 100 | assert not exists(node_dir) 101 | result = runner.invoke(webpack, ["buildall"], obj=cli_obj) 102 | assert result.exit_code == 0 103 | assert exists(bundle_js) 104 | assert exists(node_dir) 105 | 106 | 107 | def test_tpl_create(projecttpl, runner, cli_obj, app): 108 | """Test create command with template project.""" 109 | pkgfile = join(app.instance_path, "assets/package.json") 110 | assert not exists(pkgfile) 111 | result = runner.invoke(webpack, ["create"], obj=cli_obj) 112 | assert result.exit_code == 0 113 | assert "Created webpack project." in result.output 114 | assert exists(pkgfile) 115 | 116 | 117 | def test_tpl_build(projecttpl, runner, cli_obj, app): 118 | """Test build command with template project.""" 119 | bundle_js = join(app.instance_path, "assets/build/bundle.js") 120 | assert not exists(bundle_js) 121 | result = runner.invoke(webpack, ["create", "build"], obj=cli_obj) 122 | assert result.exit_code == 0 123 | assert exists(bundle_js) 124 | -------------------------------------------------------------------------------- /tests/test_ext.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017 CERN. 5 | # 6 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 7 | # it under the terms of the Revised BSD License; see LICENSE file for 8 | # more details. 9 | 10 | """Module tests.""" 11 | 12 | from flask import Flask 13 | 14 | from flask_webpackext import FlaskWebpackExt 15 | 16 | 17 | def test_version(): 18 | """Test version import.""" 19 | from flask_webpackext import __version__ 20 | 21 | assert __version__ 22 | 23 | 24 | def test_init(): 25 | """Test extension initialization.""" 26 | app = Flask("testapp") 27 | ext = FlaskWebpackExt(app) 28 | assert "flask-webpackext" in app.extensions 29 | 30 | app = Flask("testapp") 31 | ext = FlaskWebpackExt() 32 | assert "flask-webpackext" not in app.extensions 33 | ext.init_app(app) 34 | assert "flask-webpackext" in app.extensions 35 | -------------------------------------------------------------------------------- /tests/test_manifest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017 CERN. 5 | # 6 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 7 | # it under the terms of the Revised BSD License; see LICENSE file for 8 | # more details. 9 | 10 | """Module tests.""" 11 | 12 | import sys 13 | 14 | import pytest 15 | from flask import render_template_string 16 | from pywebpack import ManifestLoader 17 | 18 | from flask_webpackext.manifest import JinjaManifestLoader 19 | 20 | 21 | def test_manifest_loading(appctx, ext, project, manifest): 22 | """Test manifest loading.""" 23 | assert ext.manifest_loader == JinjaManifestLoader 24 | m = ext.manifest 25 | assert m.app 26 | assert m["app"] 27 | 28 | 29 | def test_manifest_rendering(appctx, ext, project, manifest): 30 | """Test manifest loading.""" 31 | tpl = "{{ webpack.app }}" 32 | output = '' 33 | assert render_template_string(tpl) == output 34 | 35 | 36 | def test_manifest_loader_conf(app, ext, project, manifest): 37 | """Test manifest loading.""" 38 | app.config.update( 39 | { 40 | "WEBPACKEXT_MANIFEST_LOADER": "pywebpack:ManifestLoader", 41 | } 42 | ) 43 | assert ext.manifest_loader == ManifestLoader 44 | 45 | 46 | def test_manifest_nopath(app, ext): 47 | """Test no manifest path.""" 48 | app.config["WEBPACKEXT_MANIFEST_PATH"] = None 49 | assert ext.manifest is None 50 | 51 | 52 | def test_manifest_invalid_path(app, appctx, ext): 53 | """Test no manifest path.""" 54 | app.config["WEBPACKEXT_MANIFEST_PATH"] = "invalid/path.json" 55 | 56 | pytest.raises( 57 | FileNotFoundError if sys.version_info[0] == 3 else IOError, 58 | getattr, 59 | ext, 60 | "manifest", 61 | ) 62 | -------------------------------------------------------------------------------- /tests/test_project.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Flask-WebpackExt 4 | # Copyright (C) 2017 CERN. 5 | # 6 | # Flask-WebpackExt is free software; you can redistribute it and/or modify 7 | # it under the terms of the Revised BSD License; see LICENSE file for 8 | # more details. 9 | 10 | """Module tests.""" 11 | 12 | from os.path import exists, join 13 | 14 | from flask.helpers import get_root_path 15 | from pynpm.package import PNPMPackage 16 | 17 | from flask_webpackext.project import WebpackBundleProject 18 | 19 | 20 | def test_project_path(app, projecttpl, appctx): 21 | """Test project path.""" 22 | assert projecttpl.path == app.config["WEBPACKEXT_PROJECT_BUILDDIR"] 23 | 24 | 25 | def test_project_storage_cls(ext, projecttpl, appctx): 26 | """Test project path.""" 27 | assert projecttpl.storage_cls == ext.storage_cls 28 | 29 | 30 | def test_npm_pkg_cls(app, projecttpl, appctx): 31 | """Test JS package manager class.""" 32 | app.config["WEBPACKEXT_NPM_PKG_CLS"] = "pynpm.package:PNPMPackage" 33 | assert isinstance(projecttpl.npmpkg, PNPMPackage) 34 | 35 | 36 | def test_bundle_project(projectbundle, appctx, static_folder): 37 | """Test bundle project.""" 38 | out = join(static_folder, "dist") 39 | p = projectbundle 40 | 41 | # Test create() 42 | assert not exists(p.path) 43 | p.create() 44 | assert exists(p.path) 45 | for f in ["app1.js", "app2.js", "webpack.config.js", "config.json"]: 46 | assert exists(join(p.path, f)) 47 | 48 | # Test build() 49 | files = ["app1.js", "app2.js"] 50 | assert all([not exists(join(out, f)) for f in files]) 51 | p.build() 52 | assert all([exists(join(out, f)) for f in files]) 53 | 54 | 55 | def test_super_constructor_kwargs(): 56 | """Test if passing keyword arguments to the super constructor works.""" 57 | project = WebpackBundleProject( 58 | __name__, "project", package_json_source_path="paket.json" 59 | ) 60 | assert project.package_json_source_path == join( 61 | get_root_path(__name__), "project", "paket.json" 62 | ) 63 | --------------------------------------------------------------------------------