Create webpack plugin that provides rails router helpers to the frontend at compile-time.
Currently we rely heavily on rails helpers to generate endpoint URLs for our frontend code. The pattern looks like this:
app/views/projects/pipelines/index.html.haml
%div{ 'class' => container_class }
#pipelines-list-vue{ data: { endpoint: project_pipelines_path(@project, format: :json),
"help-page-path" => help_page_path('ci/quick_start/README'),
"help-auto-devops-path" => help_page_path('topics/autodevops/index.md'),
"empty-state-svg-path" => image_path('illustrations/pipelines_empty.svg'),
"error-state-svg-path" => image_path('illustrations/pipelines_failed.svg'),
"new-pipeline-path" => new_project_pipeline_path(@project),
"can-create-pipeline" => can?(current_user, :create_pipeline, @project).to_s,
"has-ci" => @repository.gitlab_ci_yml,
"ci-lint-path" => ci_lint_path } }
app/assets/javascripts/pipelines/components/pipelines.vue
export default {
//...
data() {
const pipelinesData = document.querySelector('#pipelines-list-vue').dataset;
return {
endpoint: pipelinesData.endpoint,
helpPagePath: pipelinesData.helpPagePath,
emptyStateSvgPath: pipelinesData.emptyStateSvgPath,
errorStateSvgPath: pipelinesData.errorStateSvgPath,
autoDevopsPath: pipelinesData.helpAutoDevopsPath,
newPipelinePath: pipelinesData.newPipelinePath,
canCreatePipeline: pipelinesData.canCreatePipeline,
};
},
//...
}
Since these are all defined at compile-time, there is no reason we should need to handle these dynamically. It is messy, cumbersome, and overly-verbose.
I propose we create a simple webpack plugin which would do the following:
- Read the rails routes at compile-time and create an ES module with route index definitions
- Modify the frontend code to use helpers within the frontend codebase instead of introspecting them from the DOM:
import { help_page_path } from 'rails-route-helpers'; const autoDevopsPath = help_page_path('topics/autodevops/index.md');
- The unused rails routes should end up being purged via tree-shaking
- The bundle chunk-hashes should remain unaffected so long as this route helper module is included in a commons chunk (perhaps bundled with the webpack manifest file)
Caveats:
This may not work with all rails helpers. If we've defined one manually, it would need to be ported to the frontend.
If a rails helper requires input (like the current project ID), we'll still need to provide that via data-attributes and pass this to our helper method.
I don't know how easy it will be to parse Ruby files via JavaScript... may need some rake task to help export the helpers in some format that javascript can read.