Skip to content

Conversation

fahad19
Copy link

@fahad19 fahad19 commented Apr 17, 2017

What kind of change does this PR introduce?

New feature via externals option in css-loader, much like Webpack's core externals feature.

Did you add tests for your changes?

Yes.

If relevant, did you update the README?

Yes.

Summary

I opened an issue in css-modules repository for this first: css-modules/css-modules#227

To summarise, I want a setup like this with FrintJS:

<!-- vendors -->
<script src="lodash.js"></script>
<script src="react.js"></script>
<script src="frint.js"></script>

<!-- css-modules based framework, exposed as `window.CssFramework` -->
<script src="css-framework-using-css-modules.js"></script>

<!-- these Frint apps re-using vendors and CSS Framework from above -->
<script src="root-frint-app.js"></script>
<script src="child-frint-app-1.js"></script>
<script src="child-frint-app-2.js"></script>

Basically, I don't want Frint App bundles to include any CSS Framework code, since it has already been loaded before.

And my Webpack config for bundling Frint Apps would look like this for css-loader:

{
  test: /\.css$/,
  exclude: /node_modules/,
  use: [
    'style-loader',
    {
      loader: 'css-loader',
      options: {
        modules: true,
        importLoaders: 1,
        localIdentName: '[name]__[local]___[hash:base64:5]',

        // this is the new feature
        externals: {
          'css-framework/variables.css': 'CssFramework.variables'
        },
      }
    },
  ]
}

In any of the App bundles, when I do this:

import styles from './styles.css';

And my styles.css imports something from css-framework package:

@value variables: "css-framework/variables.css";
@value primary-color, secondary-color from variables;

.button {
  color: primary-color;
}

Instead of including the css-framework code in the bundle, it would get the values dynamically in the browser from the global window.CssFramework.variables.

Does this PR introduce a breaking change?

Possibly for old node versions, but I am happy to update them.

Other information

Fully working proof-of-concept with FrintJS here: https://github.com/fahad19/frint-css-poc

@jsf-clabot
Copy link

jsf-clabot commented Apr 17, 2017

CLA assistant check
All committers have signed the CLA.

@codecov
Copy link

codecov bot commented Apr 17, 2017

Codecov Report

Merging #496 into master will increase coverage by 0.1%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff            @@
##           master     #496     +/-   ##
=========================================
+ Coverage   98.36%   98.46%   +0.1%     
=========================================
  Files          10       11      +1     
  Lines         366      392     +26     
  Branches       87       94      +7     
=========================================
+ Hits          360      386     +26     
  Misses          6        6
Impacted Files Coverage Δ
lib/loader.js 98.85% <100%> (+0.23%) ⬆️
lib/getExternals.js 100% <100%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 868fc94...bb10eb6. Read the comment docs.

Copy link
Contributor

@bebraw bebraw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good direction. Docs + tests and it's good to go.

@michael-ciniawsky michael-ciniawsky changed the title Externals support for CSS imports feat: add externals support for CSS imports Apr 18, 2017
@fahad19
Copy link
Author

fahad19 commented Apr 18, 2017

@bebraw: awesome! I will add docs + tests very soon and update here again :D

@michael-ciniawsky
Copy link
Member

michael-ciniawsky commented Apr 18, 2017

@fahad19 Does this only work with when { modules: true } (CSSModules) are enabled ?

@fahad19
Copy link
Author

fahad19 commented Apr 18, 2017

@michael-ciniawsky: I cannot confirm it yet without tests. but manually, I only tested it with the css-modules approach, with modules: true.

@michael-ciniawsky
Copy link
Member

michael-ciniawsky commented Apr 18, 2017

Where do the externals come from? Could you give an example externals file please?

@michael-ciniawsky
Copy link
Member

michael-ciniawsky commented Apr 18, 2017

That's important, since we plan to clearly separate CSS Modules and CSS loading in the future due to perf problems in the current loader, if it works with modules exclusively we need to refactor that to options.modules. externals so it only gets trigger when in module 'mode'

@bebraw
Copy link
Contributor

bebraw commented Apr 18, 2017

@michael-ciniawsky If this is indeed CSS Modules specific, probably the smartest move would be to wait till the split happens and then push this functionality to the CSS Modules specific loader.

@fahad19
Copy link
Author

fahad19 commented Apr 18, 2017

Externals are global objects. For e.g., if css-framework.js is loaded:

<script src="css-framework.js"></script>

It would expose itself as window.CssFramework. The file would be generated from this source:

// css-framework/index.js - entry for bundle
import variables from './variables.css';
import typography from './typography.css';

export {
  variables,
  typography,
};

And the CSS files would be:

// css-frameworok/variables.css
@value primary-color: DodgerBlue;
@value secondary-color: DeepSkyBlue;

// css-framework/typography.css
.bold {
  font-weight: bold;
}

.italic {
  font-style: italic;
}

The object in the browser would look like this:

// console.log(window.CssFramework);

{
  "variables": {
    "primary-color": "DodgerBlue",
    "secondary-color": "DeepSkyBlue"
  },
  "typography": {
    "bold": "typography__bold___2AHac",
    "italic": "typography__italic___3uoRc"
  }
}

And the final output of css-framework.js bundle: https://gist.github.com/fahad19/abc46027a48c738e6ff7ca8af04a696c


When other bundles do require('css-framework')-equivalent (from .css files), instead of bundling the CSS content, it would just get the values from global object in runtime.

For other bundles, the webpack config for css-loader would be:

// some-other-app/webpack.config.js
{
  modules: true,
  localIdentName: '[name]__[local]___[hash:base64:5]',
  externals: {
    'css-framework/variables.css': 'CssFramework.variables',
    'css-framework/typography.css': 'CssFramework.typography',
  }
}

And an example css file may look like:

// some-other-app/styles.css
@value variables: "css-framework/variables.css";
@value primary-color, secondary-color from variables;

.someClass {
  composes: bold from "css-framework/typography.css";
  color: primary-color;
}

@fahad19
Copy link
Author

fahad19 commented Apr 18, 2017

currently, my needs are css-modules specific. I am happy to wait until the split happens. but if you think this feature can apply to both scenarios, that's even better I guess.

fahad19 added 3 commits April 25, 2017 00:59
* master:
  fix: case insensitivity of @import (webpack-contrib#514)
  chore: update comment (webpack-contrib#515)
  docs(README): improve importLoaders section and example (webpack-contrib#512)
  docs(README): fix link (webpack-contrib#508)
  docs(README): fix typo in example (webpack-contrib#507)
  docs(README): fix typo in maintainers link (webpack-contrib#505)
  fix: imported variables are replaced in exports if followed by a comma (webpack-contrib#504)
  docs(README): standardize (webpack-contrib#503)
  test: `charset` directive (webpack-contrib#502)
  fix: url with a trailing space is now handled correctly (webpack-contrib#494)
  fix: use `btoa` instead `Buffer` (webpack-contrib#501)
  test: add test for escaped characters (webpack-contrib#493)
  test: add tests for encoded svg data uri (webpack-contrib#492)
  test: add tests when css contain data uri and source maps are enabled (webpack-contrib#491)
  fix: loader now correctly handles `url` with space(s) (webpack-contrib#495)
@fahad19
Copy link
Author

fahad19 commented Apr 24, 2017

  • Tests added
  • README updated
  • PR body updated to reflect the last few commits

The feature being added does not require modules: true, as shown in the tests.

@fahad19
Copy link
Author

fahad19 commented Apr 27, 2017

conflicts taken care of. up for final review.

/cc @michael-ciniawsky @bebraw

lib/loader.js Outdated
var sourceMap = query.sourceMap || false;
var resolve = createResolver(query.alias);

var givenExternals = query.externals || (this.externals || {});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic would work better in a function of its own.

lib/loader.js Outdated

var externalsKeys = Object.keys(externals);

function findExternalFromImportUrl(importUrl) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would push this function outside to root scope.

@michael-ciniawsky
Copy link
Member

michael-ciniawsky commented Apr 29, 2017

@fahad19 Also hold on with this a bit longer, I have the groundwork for the next major of css-loader (no CSS Modules) ready locally and after that, I would like to move on with this feature here 😛

@fahad19
Copy link
Author

fahad19 commented May 1, 2017

@bebraw: feedback taken care of.

@michael-ciniawsky: sure. please let me know when you are ready.

Copy link
Member

@joshwiens joshwiens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I stand corrected about the modules. Regardless of that, all pull requests > semver: Patch are being held until Tobias is finished with https://github.com/webpack-contrib/css-loader/tree/new-loader for the sake of saving his sanity.

Given the nature of the change, once merged this feature will exist initially in the existing Major release and we can discuss if it makes sense in the 1.0.0 version once it's stabilized.

@michael-ciniawsky
Copy link
Member

Yep same as in #421 for the meantime

@fahad19
Copy link
Author

fahad19 commented May 3, 2017

@d3viant0ne: thanks for the explanation!

just to clarify again, this new externals feature is not dependent on CSS Modules. it is intended to work with base css-loader.

@michael-ciniawsky
Copy link
Member

michael-ciniawsky commented Jan 4, 2018

Sry but I have to declined this PR for now, since css-loader v1.0.0 will be a complete overhaul starting with a minimal design

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants