-
Notifications
You must be signed in to change notification settings - Fork 530
WIP: Prototype of rollup_bundle with code splitting #104
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,6 @@ | |
| // For Windows, we must deep-import the actual .js file, not rely on reading the "main" from package.json | ||
| const rollup = require('rollup/dist/rollup'); | ||
| const nodeResolve = require('rollup-plugin-node-resolve/dist/rollup-plugin-node-resolve.cjs'); | ||
| const commonjs = require('rollup-plugin-commonjs/dist/rollup-plugin-commonjs.cjs'); | ||
| const path = require('path'); | ||
|
|
||
| const binDirPath = "TMPL_bin_dir_path"; | ||
|
|
@@ -53,12 +52,14 @@ class NormalizePaths { | |
| } | ||
|
|
||
| export default { | ||
| output: {format: 'iife'}, | ||
| input: [TMPL_inputs], | ||
| output: {dir: path.join(process.cwd(), binDirPath, buildFileDirname, 'bundles.es6'), format: 'cjs'}, | ||
| experimentalCodeSplitting: true, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not that we're really rolling it out yet - but I think we should consider exposing an experimental flag as a rule attribute when we enable these things - we could have users depend on us to provide a higher guarantee than the thing we depend on |
||
| experimentalDynamicImport: true, | ||
| plugins: [ | ||
| TMPL_additional_plugins | ||
| ].concat([ | ||
| new NormalizePaths(), | ||
| commonjs(), | ||
|
||
| nodeResolve({jsnext: true, module: true}), | ||
| ]) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,7 +32,12 @@ def write_rollup_config(ctx, plugins=[]): | |
| config = ctx.actions.declare_file("_%s.rollup.conf.js" % ctx.label.name) | ||
|
|
||
| # build_file_path includes the BUILD.bazel file, transform here to only include the dirname | ||
| buildFileDirname = "/".join(ctx.build_file_path.split("/")[:-1]) | ||
| build_file_dirname = "/".join(ctx.build_file_path.split("/")[:-1]) | ||
|
|
||
| entry_points = [] | ||
| for e in ctx.attr.entry_points: | ||
| entry_points = entry_points + ["\""+"/".join([ctx.workspace_name, e])+"\""] | ||
| entry_points = ",".join(entry_points) | ||
|
|
||
| mappings = dict() | ||
| all_deps = ctx.attr.deps + ctx.attr.srcs | ||
|
|
@@ -48,83 +53,128 @@ def write_rollup_config(ctx, plugins=[]): | |
| output = config, | ||
| template = ctx.file._rollup_config_tmpl, | ||
| substitutions = { | ||
| "TMPL_inputs": entry_points, | ||
| "TMPL_bin_dir_path": ctx.bin_dir.path, | ||
| "TMPL_workspace_name": ctx.workspace_name, | ||
| "TMPL_build_file_dirname": buildFileDirname, | ||
| "TMPL_build_file_dirname": build_file_dirname, | ||
| "TMPL_label_name": ctx.label.name, | ||
| "TMPL_module_mappings": str(mappings), | ||
| "TMPL_additional_plugins": ",\n".join(plugins), | ||
| }) | ||
|
|
||
| return config | ||
|
|
||
| def run_rollup(ctx, config, output): | ||
| entryPoint = "/".join([ctx.workspace_name, ctx.attr.entry_point]) | ||
|
|
||
| def run_rollup(ctx, config): | ||
| args = ctx.actions.args() | ||
| args.add(["--config", config.path]) | ||
| args.add(["--output.file", output.path]) | ||
| args.add(["--input", entryPoint]) | ||
|
|
||
| es6_sources = collect_es6_sources(ctx) | ||
|
|
||
| output_dir = ctx.actions.declare_directory("bundles.es6") | ||
|
|
||
| ctx.action( | ||
| executable = ctx.executable._rollup, | ||
| inputs = es6_sources + ctx.files.node_modules + [config], | ||
| outputs = [output], | ||
| outputs = [output_dir], | ||
| arguments = [args] | ||
| ) | ||
|
|
||
| def run_tsc(ctx, input, output): | ||
| args = ctx.actions.args() | ||
| args.add(["--target", "es5"]) | ||
| args.add("--allowJS") | ||
| args.add(input.path) | ||
| args.add(["--outFile", output.path]) | ||
| return output_dir | ||
|
|
||
| ctx.action( | ||
| executable = ctx.executable._tsc, | ||
| inputs = [input], | ||
| outputs = [output], | ||
| arguments = [args] | ||
| ) | ||
| def run_tsc(ctx, input_dir): | ||
| config = ctx.actions.declare_file("_%s.tsconfig.json" % ctx.label.name) | ||
|
|
||
| output_dir = ctx.actions.declare_directory("bundles.es5") | ||
|
|
||
| def run_uglify(ctx, input, output, debug = False): | ||
| config = ctx.actions.declare_file("_%s%s.uglify.json" % ( | ||
| ctx.label.name, ".debug" if debug else "")) | ||
| build_file_dirname = ctx.build_file_path.split("/")[:-1] | ||
| input_dir_rerooted = "/".join(input_dir.short_path.split("/")[len(build_file_dirname):]) | ||
| output_dir_rerooted = "/".join(output_dir.short_path.split("/")[len(build_file_dirname):]) | ||
|
|
||
| ctx.actions.expand_template( | ||
| output = config, | ||
| template = ctx.file._uglify_config_tmpl, | ||
| template = ctx.file._tsconfig_tmpl, | ||
| substitutions = { | ||
| "TMPL_mangle": "false" if debug else "true" | ||
| }, | ||
| "TMPL_include_path": input_dir_rerooted + "/*", | ||
| "TMPL_out_dir": output_dir_rerooted, | ||
| }) | ||
|
|
||
| args = ctx.actions.args() | ||
| args.add(["--project", config.path]) | ||
|
|
||
| ctx.action( | ||
| executable = ctx.executable._tsc, | ||
| inputs = [input_dir, config], | ||
| outputs = [output_dir], | ||
| arguments = [args] | ||
| ) | ||
|
|
||
| return output_dir | ||
|
|
||
| def run_uglify(ctx, input_dir, output_dir, debug = False): | ||
| args = ctx.actions.args() | ||
| args.add(input.path) | ||
| args.add(["--config-file", config.path]) | ||
| args.add(["--output", output.path]) | ||
| args.add(input_dir.path) | ||
| args.add(output_dir.path) | ||
| if debug: | ||
| args.add("--beautify") | ||
| args.add("--debug") | ||
|
|
||
| ctx.action( | ||
| executable = ctx.executable._uglify, | ||
| inputs = [input, config], | ||
| outputs = [output], | ||
| inputs = [input_dir], | ||
| outputs = [output_dir], | ||
| arguments = [args] | ||
| ) | ||
|
|
||
| def _generate_html(ctx): | ||
| if len(ctx.attr.entry_points) == 0: | ||
| fail("\n%s: at least one entry_point must be specified\n" % ctx.label.name) | ||
| build_file_prefix = "/".join(ctx.build_file_path.split("/")[:-1]) + "/" | ||
| main_entry_point = ctx.attr.entry_points[0].lstrip(build_file_prefix) | ||
| entry_points = {} | ||
| for e in ctx.attr.entry_points: | ||
| entry_point = e.lstrip(build_file_prefix) | ||
| entry_points["./" + entry_point] = "bundles.es5_min/" + entry_point.split("/")[-1] | ||
| rollup_scripts = """<script src="/system.js"></script> | ||
| <script> | ||
| (function (global) { | ||
| System.config({ | ||
| packages: { | ||
| '' : { | ||
| map: """ + str(entry_points) + """, | ||
| defaultExtension: 'js' | ||
| }, | ||
| } | ||
| }); | ||
| })(this); | ||
| </script> | ||
| <script> | ||
| System.import('""" + main_entry_point + """').catch(function(err){ console.error(err); }); | ||
| </script> | ||
| """ | ||
| ctx.actions.expand_template( | ||
| output = ctx.outputs.index_html, | ||
| template = ctx.file.index_html_template, | ||
| substitutions = { | ||
| "TEMPLATED_rollup_scripts": rollup_scripts, | ||
| }) | ||
|
|
||
| def _rollup_bundle(ctx): | ||
| rollup_config = write_rollup_config(ctx) | ||
| run_rollup(ctx, rollup_config, ctx.outputs.build_es6) | ||
| run_tsc(ctx, ctx.outputs.build_es6, ctx.outputs.build_es5) | ||
| run_uglify(ctx, ctx.outputs.build_es5, ctx.outputs.build_es5_min) | ||
| run_uglify(ctx, ctx.outputs.build_es5, ctx.outputs.build_es5_min_debug, debug = True) | ||
| return DefaultInfo(files=depset([ctx.outputs.build_es5_min])) | ||
| output_dir_es6 = run_rollup(ctx, rollup_config) | ||
| output_dir_es5 = run_tsc(ctx, output_dir_es6) | ||
| output_dir_es5_min = ctx.actions.declare_directory("bundles.es5_min") | ||
| output_dir_es5_min_debug = ctx.actions.declare_directory("bundles.es5_min_debug") | ||
| run_uglify(ctx, output_dir_es5, output_dir_es5_min) | ||
| run_uglify(ctx, output_dir_es5, output_dir_es5_min_debug, debug = True) | ||
| _generate_html(ctx) | ||
| ctx.actions.expand_template( | ||
| output = ctx.outputs.system_js, | ||
| template = ctx.file._systemjs, | ||
| substitutions = {}) | ||
| return DefaultInfo(runfiles=ctx.runfiles([output_dir_es6, output_dir_es5, output_dir_es5_min, output_dir_es5_min_debug, ctx.outputs.system_js, ctx.outputs.index_html]), files=depset([])) | ||
|
|
||
| ROLLUP_ATTRS = { | ||
| "entry_point": attr.string(mandatory = True), | ||
| "entry_points": attr.string_list(mandatory = True), | ||
| "index_html_template": attr.label(allow_files = [".template.html"], single_file = True), | ||
| "srcs": attr.label_list(allow_files = [".js"]), | ||
| "deps": attr.label_list(aspects = [rollup_module_mappings_aspect]), | ||
| "node_modules": attr.label(default = Label("@//:node_modules")), | ||
|
|
@@ -140,6 +190,14 @@ ROLLUP_ATTRS = { | |
| executable = True, | ||
| cfg="host", | ||
| default = Label("@build_bazel_rules_nodejs//internal/rollup:uglify")), | ||
| "_systemjs": attr.label( | ||
| default = Label("@build_bazel_rules_nodejs_rollup_deps//:node_modules/systemjs/dist/system.js"), | ||
| allow_files = True, | ||
| single_file = True), | ||
| "_tsconfig_tmpl": attr.label( | ||
| default = Label("@build_bazel_rules_nodejs//internal/rollup:tsconfig.json"), | ||
| allow_files = True, | ||
| single_file = True), | ||
| "_rollup_config_tmpl": attr.label( | ||
| default = Label("@build_bazel_rules_nodejs//internal/rollup:rollup.config.js"), | ||
| allow_files = True, | ||
|
|
@@ -150,15 +208,11 @@ ROLLUP_ATTRS = { | |
| single_file = True), | ||
| } | ||
|
|
||
| ROLLUP_OUTPUTS = { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can't land it if we remove these. Can we still output the files for the "main" bundle or something?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could make it so that the rule could output both a regular bundle or a code split one but without a devserver that can support code splitting is there any value in a landing the production bundler at this point?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we need to land this somewhere with CI so that it doesn't rust, and people can try it and build on it. |
||
| "build_es6": "%{name}.es6.js", | ||
| "build_es5": "%{name}.js", | ||
| "build_es5_min": "%{name}.min.js", | ||
| "build_es5_min_debug": "%{name}.min_debug.js", | ||
| } | ||
|
|
||
| rollup_bundle = rule( | ||
| implementation = _rollup_bundle, | ||
| attrs = ROLLUP_ATTRS, | ||
| outputs = ROLLUP_OUTPUTS, | ||
| outputs = { | ||
| "system_js": "system.js", | ||
| "index_html": "index.html", | ||
| } | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| { | ||
| "compilerOptions": { | ||
| "target": "es5", | ||
| "lib": ["es6"], | ||
| "allowJs": true, | ||
| "outDir": "TMPL_out_dir" | ||
| }, | ||
| "include": [ | ||
| "TMPL_include_path" | ||
| ], | ||
| "exclude": [] | ||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| /** | ||
| * @license | ||
| * Copyright 2017 The Bazel Authors. All rights reserved. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * | ||
| * You may obtain a copy of the License at | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| const UglifyJS = require("uglify-js"); | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
|
|
||
| if (process.argv.length < 4) { | ||
| throw new Error("input_path and output_path arguments required"); | ||
| } | ||
|
|
||
| const inputPath = process.argv[2]; | ||
| const outputPath = process.argv[3]; | ||
| const args = process.argv.slice(4); | ||
| let debug = false; | ||
| args.forEach(a => { | ||
| if (a === '--debug') { | ||
| debug = true; | ||
| } | ||
| }) | ||
|
|
||
| const uglifyOptions = { | ||
| "compress": { | ||
| "pure_getters": true, | ||
| "passes": 3, | ||
| "global_defs": { | ||
| "ngDevMode": false | ||
| } | ||
| }, | ||
| "mangle": !debug | ||
| }; | ||
|
|
||
| if (!fs.existsSync(outputPath)){ | ||
| fs.mkdirSync(outputPath); | ||
| } | ||
| const dir = fs.readdirSync(inputPath); | ||
| dir.forEach(f => { | ||
| const inputFile = path.join(inputPath, path.basename(f)); | ||
| const outputFile = path.join(outputPath, path.basename(f)); | ||
| console.log(`Minifying ${inputFile} -> ${outputFile}`); | ||
| const code = fs.readFileSync(inputFile, {encoding: 'utf-8'}); | ||
| const result = UglifyJS.minify(code, uglifyOptions); | ||
| if (result.error) { | ||
| throw result.error; | ||
| } | ||
| fs.writeFileSync(outputFile, result.code, 'utf8'); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
experimental code splitting only supports 'cjs' right now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need a formatter in this repo