Merge pull request #6765 from edx/andya/requirejs-in-lms
Add RequireJS to the LMS
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
from edxmako.shortcuts import render_to_string
|
||||
from django.conf import settings as django_settings
|
||||
from staticfiles.storage import staticfiles_storage
|
||||
|
||||
from pipeline.conf import settings
|
||||
from pipeline.packager import Packager
|
||||
@@ -79,3 +81,78 @@ def render_individual_js(package, paths, templates=None):
|
||||
if templates:
|
||||
tags.append(render_inline_js(package, templates))
|
||||
return '\n'.join(tags)
|
||||
|
||||
|
||||
def render_require_js_path_overrides(path_overrides): # pylint: disable=invalid-name
|
||||
"""Render JavaScript to override default RequireJS paths.
|
||||
|
||||
The Django pipeline appends a hash to JavaScript files,
|
||||
so if the JS asset isn't included in the bundle for the page,
|
||||
we need to tell RequireJS where to look.
|
||||
|
||||
For example:
|
||||
|
||||
"js/vendor/jquery.min.js" --> "js/vendor/jquery.min.abcd1234"
|
||||
|
||||
We would then add a line in a <script> tag:
|
||||
|
||||
require.paths['jquery'] = 'js/vendor/jquery.min.abcd1234'
|
||||
|
||||
so that any reference to 'jquery' in a JavaScript module
|
||||
will cause RequireJS to load '/static/js/vendor/jquery.min.abcd1234.js'
|
||||
|
||||
If running in DEBUG mode (as in devstack), the resolved JavaScript URLs
|
||||
won't contain hashes, so the new paths will match the original paths.
|
||||
|
||||
Arguments:
|
||||
path_overrides (dict): Mapping of RequireJS module names to
|
||||
filesystem paths.
|
||||
|
||||
Returns:
|
||||
unicode: The HTML of the <script> tag with the path overrides.
|
||||
|
||||
"""
|
||||
# Render the <script> tag that overrides the paths defined in `require.paths`
|
||||
# Note: We don't use a Mako template to render this because Mako apparently
|
||||
# acquires a lock when loading templates, which can lead to a deadlock if
|
||||
# this function is called from within another template.
|
||||
html = ['<script type="text/javascript">']
|
||||
|
||||
# The rendered <script> tag with overrides should be included *after*
|
||||
# the application's RequireJS config, which defines a `require` object.
|
||||
# Just in case the `require` object hasn't been loaded, we create a default
|
||||
# object. This will avoid a JavaScript error that might cause the rest of the
|
||||
# page to fail; however, it may mean that these overrides won't be available
|
||||
# to RequireJS.
|
||||
html.extend([
|
||||
'var require = require || {};',
|
||||
'require.paths = require.paths || [];'
|
||||
])
|
||||
|
||||
# Specify override the base URL to point to STATIC_URL
|
||||
html.append(
|
||||
"require.baseUrl = '{url}'".format(
|
||||
url=django_settings.STATIC_URL
|
||||
)
|
||||
)
|
||||
|
||||
for module, url_path in path_overrides.iteritems():
|
||||
# Calculate the full URL, including any hashes added to the filename by the pipeline.
|
||||
# This will also include the base static URL (for example, "/static/") and the
|
||||
# ".js" extension.
|
||||
actual_url = staticfiles_storage.url(url_path)
|
||||
|
||||
# RequireJS assumes that every file it tries to load has a ".js" extension, so
|
||||
# we need to remove ".js" from the module path.
|
||||
# RequireJS also already has a base URL set to the base static URL, so we can remove that.
|
||||
path = actual_url.replace('.js', '').replace(django_settings.STATIC_URL, '')
|
||||
|
||||
# Add the path override to the inline JavaScript.
|
||||
html.append(
|
||||
"require.paths['{module}'] = '{path}';".format(
|
||||
module=module,
|
||||
path=path
|
||||
)
|
||||
)
|
||||
html.append('</script>')
|
||||
return "\n".join(html)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
from staticfiles.storage import staticfiles_storage
|
||||
from pipeline_mako import compressed_css, compressed_js
|
||||
from django.utils.translation import get_language_bidi
|
||||
from require.templatetags.require import require_module
|
||||
%>
|
||||
|
||||
<%def name='url(file, raw=False)'><%
|
||||
@@ -37,6 +38,10 @@ except:
|
||||
%endif
|
||||
</%def>
|
||||
|
||||
<%def name='require_module(module)'>
|
||||
${require_module(module)}
|
||||
</%def>
|
||||
|
||||
<%def name="include(path)"><%
|
||||
from django.template.loaders.filesystem import _loader
|
||||
source, template_path = _loader.load_template_source(path)
|
||||
|
||||
0
common/djangoapps/pipeline_mako/tests/__init__.py
Normal file
0
common/djangoapps/pipeline_mako/tests/__init__.py
Normal file
29
common/djangoapps/pipeline_mako/tests/test_render.py
Normal file
29
common/djangoapps/pipeline_mako/tests/test_render.py
Normal file
@@ -0,0 +1,29 @@
|
||||
"""Tests for rendering functions in the mako pipeline. """
|
||||
|
||||
from django.test import TestCase
|
||||
from pipeline_mako import render_require_js_path_overrides
|
||||
|
||||
|
||||
class RequireJSPathOverridesTest(TestCase):
|
||||
"""Test RequireJS path overrides. """
|
||||
|
||||
OVERRIDES = {
|
||||
'jquery': 'js/vendor/jquery.min.js',
|
||||
'backbone': 'js/vendor/backbone-min.js',
|
||||
'text': 'js/vendor/text.js'
|
||||
}
|
||||
|
||||
OVERRIDES_JS = (
|
||||
"<script type=\"text/javascript\">\n"
|
||||
"var require = require || {};\n"
|
||||
"require.paths = require.paths || [];\n"
|
||||
"require.baseUrl = '/static/'\n"
|
||||
"require.paths['jquery'] = 'js/vendor/jquery.min';\n"
|
||||
"require.paths['text'] = 'js/vendor/text';\n"
|
||||
"require.paths['backbone'] = 'js/vendor/backbone-min';\n"
|
||||
"</script>"
|
||||
)
|
||||
|
||||
def test_requirejs_path_overrides(self):
|
||||
result = render_require_js_path_overrides(self.OVERRIDES)
|
||||
self.assertEqual(result, self.OVERRIDES_JS)
|
||||
Reference in New Issue
Block a user