示例#1
0
def _process_loaders_paths(toolchain, spec, loaders_paths_map):
    """
    This function processes the loaders_paths_map in place into a form
    that may be encoded into JSON
    """

    fake_spec = {
        CALMJS_LOADERPLUGIN_REGISTRY: spec.get(CALMJS_LOADERPLUGIN_REGISTRY),
        WEBPACK_RESOLVELOADER_ALIAS: {},
    }
    # work with this copy for the mean time before applying the maps
    # back
    filtered_loaders_paths_map = normalize_and_register_webpackloaders(
        fake_spec, loaders_paths_map)
    spec_update_sourcepath_filter_loaderplugins(fake_spec,
                                                filtered_loaders_paths_map,
                                                'default')
    toolchain_spec_prepare_loaderplugins(toolchain, fake_spec, 'testloaders',
                                         WEBPACK_RESOLVELOADER_ALIAS)
    # borrow the private entry generator by the toolchain.
    entries = toolchain._gen_modname_source_target_modpath(
        spec, fake_spec['testloaders_sourcepath'])
    # manually trigger the compile entries using the loaderplugin rules.
    modpaths, targetpaths, export_module_names = process_compile_entries(
        toolchain.compile_loaderplugin_entry, spec, entries)
    # the targets will be injected into the alias.
    config = spec[karma.KARMA_CONFIG]

    webpack_conf = config['webpack']
    # directly update these as aliases.
    resolve = dict_setget_dict(webpack_conf, 'resolve')
    resolve_alias = dict_setget_dict(resolve, 'alias')

    for modname, p in targetpaths.items():
        # add the finalized modname as alaises.
        resolve_alias[modname] = join(spec[BUILD_DIR], normpath(p))
        # also remove it from the test module paths map as these are not
        # tests.
        spec[TEST_MODULE_PATHS_MAP].pop(modname, None)

    # since the registry should be the same, assume the results are
    # as expected; so just do a simple merge.
    resolve_loader = dict_setget_dict(webpack_conf, 'resolveLoader')
    resolve_loader_alias = dict_setget_dict(resolve_loader, 'alias')
    resolve_loader_alias.update(fake_spec[WEBPACK_RESOLVELOADER_ALIAS])
    update_spec_webpack_loaders_modules(fake_spec, resolve_alias)
    # also grab the extra loader rules that got generated
    loaders = fake_spec.get(WEBPACK_MODULE_RULES, [])
    if loaders:
        rules = _apply_webpack_module_rules(webpack_conf)
        rules.extend(loaders)

    # grab all the raw modpath keys and store them for the module
    # generation process later.
    spec[TEST_LOADER_MODNAMES] = set(modpaths)
    # update the actual mapping
    loaders_paths_map.clear()
    loaders_paths_map.update(filtered_loaders_paths_map)
示例#2
0
    def test_update_spec_webpack_loaders_modules(self):
        spec = Spec(calmjs_webpack_modname_loader_map={
            'some/style.css': ['style', 'css'],
        }, )
        alias = {
            'some/style.css': '/path/to/some/style.css',
        }
        update_spec_webpack_loaders_modules(spec, alias)

        self.assertEqual([{
            'test': '/path/to/some/style.css',
            'loaders': ['style', 'css'],
        }], spec['webpack_module_rules'])
示例#3
0
    def test_update_spec_webpack_loaders_modules_missing_alias(self):
        spec = Spec(calmjs_webpack_modname_loader_map={
            'some/style.css': ['style', 'css'],
        }, )
        alias = {}
        with pretty_logging(stream=StringIO()) as s:
            update_spec_webpack_loaders_modules(spec, alias)

        self.assertIn(
            "WARNING modname 'some/style.css' requires loader chain "
            "['style', 'css'] but it does not have a corresponding webpack "
            "resolve.alias; webpack build failure may result as loaders are "
            "not configured for this modname",
            s.getvalue(),
        )

        self.assertEqual([], spec['webpack_module_rules'])
示例#4
0
 def test_update_spec_webpack_loaders_modules_empty(self):
     spec = Spec()
     alias = {}
     update_spec_webpack_loaders_modules(spec, alias)
     self.assertEqual([], spec['webpack_module_rules'])
示例#5
0
    def assemble(self, spec):
        """
        Assemble the library by compiling everything and generate the
        required files for the final bundling.
        """
        def generate_alias(prefix):
            alias = {}
            key = prefix + self.targetpath_suffix
            for modname, target in spec.get(key, {}).items():
                # the alias must point to the full path.
                alias[modname] = join(spec[BUILD_DIR], *target.split('/'))
            return alias

        # the build config is the file that will be passed to webpack for
        # building the final bundle.
        webpack_config = WebpackConfig({
            'mode':
            spec.get(WEBPACK_MODE, DEFAULT_WEBPACK_MODE),
            'devtool':
            spec.get(WEBPACK_DEVTOOL, DEFAULT_WEBPACK_DEVTOOL),
            'output': {
                'path': dirname(spec[EXPORT_TARGET]),
                'filename': basename(spec[EXPORT_TARGET]),
                # TODO determine if publicPath is needed.

                # TODO these are using magic values.  The library target
                # should be configured, along with umdNamedDefine also
                # when the way to expose the relevant options as proper
                # sets are determined.
                'libraryTarget': 'umd',
                'umdNamedDefine': True,
            },
            'resolve': {},
            # TODO should omit this if no alias are found
            'resolveLoader': {
                'alias': spec.get(WEBPACK_RESOLVELOADER_ALIAS, {}),
            },
            'externals':
            spec.get(WEBPACK_EXTERNALS, {}),
            'module': {},
        })
        if spec.get(WEBPACK_OPTIMIZE_MINIMIZE):
            webpack_config['optimization'] = {'minimize': True}
        if WEBPACK_OUTPUT_LIBRARY in spec:
            webpack_config['output']['library'] = spec[WEBPACK_OUTPUT_LIBRARY]

        version = get_bin_version(
            spec[self.webpack_bin_key],
            kw={
                'env':
                webpack_env(pathsep.join(self.find_node_modules_basedir())),
            })

        logger.debug("found webpack at '%s' to be version '%s'",
                     spec[self.webpack_bin_key], version)
        webpack_config['__webpack_target__'] = version

        # set up alias lookup mapping.
        webpack_config['resolve']['alias'] = alias = {}

        # generate the aliases - yes, we include the bundled sources to
        # be explicit as there are cases where an alternative bundle may
        # be specified using optional advices.
        main_prefixes = (
            'transpiled',
            'bundled',
        )
        source_alias = {}
        for prefix in main_prefixes:
            source_alias.update(generate_alias(prefix))

        # Do the same for loaders, but keep it in a separate mapping for
        # now.
        other_prefixes = ('loaderplugins', )
        other_alias = {}
        for prefix in other_prefixes:
            other_alias.update(generate_alias(prefix))

        # It is assumed that if WEBPACK_ENTRY_POINT is defined, it will
        # resolve into a target through the generated alias mapping.
        # Otherwise, assume one of the default calmjs style exports.
        if (spec.get(WEBPACK_ENTRY_POINT,
                     DEFAULT_BOOTSTRAP_EXPORT) == DEFAULT_BOOTSTRAP_EXPORT):
            # now resolve whether the webpack.externals has been defined
            # in a manner that requires the complete lookup module
            logger.info("spec webpack_entry_point defined to be '%s'",
                        DEFAULT_BOOTSTRAP_EXPORT)
            if (webpack_config['externals'].get(DEFAULT_BOOTSTRAP_EXPORT) ==
                    DEFAULT_BOOTSTRAP_EXPORT_CONFIG):
                logger.info(
                    "webpack.externals defined '%s' with value that enables "
                    "the calmjs webpack bootstrap module; generating module "
                    "with the complete bootstrap template",
                    DEFAULT_BOOTSTRAP_EXPORT)
                # assign the internal loader to the alias
                # TODO check that the default loader not being passed
                # through check_all_alias_declared is not an issue.
                alias[DEFAULT_CALMJS_EXPORT_NAME] = self.write_lookup_module(
                    spec, _DEFAULT_LOADER_FILENAME,
                    *_WEBPACK_CALMJS_MODULE_LOADER_TEMPLATE)
                # the bootstrap module will be the entry point in this
                # case.
                webpack_config['entry'] = self.write_bootstrap_module(spec)

                if (spec.get(WEBPACK_OUTPUT_LIBRARY) !=
                        DEFAULT_BOOTSTRAP_EXPORT):
                    # a simple warning will do, as this may only be an
                    # inconvenience.
                    logger.warning(
                        "exporting complete calmjs bootstrap module with "
                        "webpack.output.library as '%s' (expected '%s')",
                        spec.get(WEBPACK_OUTPUT_LIBRARY),
                        DEFAULT_BOOTSTRAP_EXPORT,
                    )
            else:
                logger.info(
                    "webpack.externals does not have '%s' defined for "
                    "the complete calmjs webpack bootstrap module; "
                    "generating simple export of modules",
                    DEFAULT_BOOTSTRAP_EXPORT)

                # one key bit: to avoid the default webpack behavior of
                # potentially overriding values on the root node (say,
                # there exists window.modules already by some other
                # package), only use the template that exports to module
                # if that is defined; otherwise simply use the load only
                # template that will just require the selected modules.
                if spec.get(WEBPACK_OUTPUT_LIBRARY):
                    template = _WEBPACK_ENTRY_CALMJS_EXPORT_ONLY_TEMPLATE
                else:
                    template = _WEBPACK_ENTRY_CALMJS_LOAD_ONLY_TEMPLATE

                # the resulting file is the entry point.
                webpack_config['entry'] = self.write_lookup_module(
                    spec, _DEFAULT_BOOTSTRAP_FILENAME, *template)
                if (spec.get(WEBPACK_OUTPUT_LIBRARY) ==
                        DEFAULT_BOOTSTRAP_EXPORT):
                    logger.critical(
                        "cowardly aborting export to webpack.output.library "
                        "as '%s' without the complete bootstrap; generating "
                        "module with export only template",
                        DEFAULT_BOOTSTRAP_EXPORT,
                    )
                    raise ValueError(
                        "aborting export of webpack.output.library as '%s' "
                        "with incomplete settings and bootstrap module" %
                        DEFAULT_BOOTSTRAP_EXPORT)
        else:
            # need to manually resolve the entry
            # if externals has been defined, use the complete lookup module
            # otherwise, use the simplified version.
            wp_ep = spec[WEBPACK_ENTRY_POINT]
            if wp_ep not in source_alias:
                msg = "'%s' not found in the source alias map" % wp_ep
                logger.error(msg)
                logger.info(
                    'source alias map {alias: targetpath}: %s',
                    json_dumps(source_alias),
                )
                raise ToolchainAbort(msg)
            webpack_config['entry'] = source_alias[wp_ep]

        # merge all aliases for writing of configuration file
        alias.update(source_alias)
        alias.update(other_alias)
        # record the webpack config to the spec
        spec[WEBPACK_CONFIG] = webpack_config

        if spec.get(VERIFY_IMPORTS, True):
            missing = self.check_all_alias_declared(
                source_alias,
                partial(
                    check_name_declared,
                    webpack_config['resolve']['alias'],
                    webpack_config['resolveLoader']['alias'],
                    webpack_config['externals'],
                    spec.get(CALMJS_LOADERPLUGIN_REGISTRY),
                ))
            if missing:
                logger.warning(
                    "source file(s) referenced modules that are not in alias "
                    "or externals: %s",
                    ', '.join(sorted(repr_compat(m) for m in missing)))

        update_spec_webpack_loaders_modules(spec, alias)
        webpack_config['module']['rules'] = spec.get(WEBPACK_MODULE_RULES, [])

        # write the configuration file, after everything is checked.
        self.write_webpack_config(spec, webpack_config)