Skip to content
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

Webpack loader #186

Merged
merged 11 commits into from
Dec 14, 2017
Merged

Webpack loader #186

merged 11 commits into from
Dec 14, 2017

Conversation

zamotany
Copy link
Contributor

@zamotany zamotany commented Dec 13, 2017

Fixes #73, #169

Documentation is missing, but I'll make it once the code will be done.

So the JS rule looks like this:

{
  test: /\.js$/,
  use: [
    { loader: 'babel-loader', options: { cacheDirectory: true } },
    { loader: 'linaria/loader' }
  ],
},

Then while testing on website:

  • changing theme.js rebuilds CSS so HMR updates styles
  • babel cache is not a problem anymore
  • deleting .linaria-cache doesn't break anything

@codecov
Copy link

codecov bot commented Dec 13, 2017

Codecov Report

Merging #186 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##           master     #186   +/-   ##
=======================================
  Coverage   97.64%   97.64%           
=======================================
  Files          19       19           
  Lines         425      425           
  Branches       90       90           
=======================================
  Hits          415      415           
  Misses         10       10

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 3b894e5...e124b4b. Read the comment docs.

@@ -0,0 +1 @@
module.exports = require('./build/tools/webpack-loader').default;
Copy link
Member

Choose a reason for hiding this comment

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

We want to publish this file, please add it to "files" in package.json

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -50,7 +50,7 @@ module.exports = (env = { NODE_ENV: 'development' }) => ({
{
test: /\.js$/,
exclude: /node_modules/,
use: { loader: 'babel-loader' },
use: [{ loader: 'babel-loader' }, { loader: 'linaria/loader' }],
Copy link
Member

Choose a reason for hiding this comment

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

Let's enable cache for babel-loader here to make sure we always test against it

};
}

function makeLoaderAdapter(fn) {
Copy link
Member

Choose a reason for hiding this comment

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

This abstraction seems unnecessary. Why not call the function directly instead of creating a higher order function to which you pass it as an argument? We don't seem to need it to reuse anywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I got it done, before I found a perfect solution and back them the whole loader was async making it harder to integrate with webpack.


// `transformFromAst` is synchronous in Babel 6, but async in Babel 7 hence
// the `transformFromAstSync`.
return (babel.transformFromAstSync || babel.transformFromAst)(
Copy link
Member

Choose a reason for hiding this comment

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

Probably better to use the async babel.transformFromAst

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is no async version of transformFromAst in Babel 6.

Copy link
Member

@satya164 satya164 Dec 14, 2017

Choose a reason for hiding this comment

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

Yes, I meant always use babel.transformFromAst, sync or async. You were handling promises anyway.

}

function makeLoaderAdapter(fn) {
function loaderAdapter(...args: any[]) {
Copy link
Member

Choose a reason for hiding this comment

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

This code can be hugely simplified by making the result always async:

const callback = this.async();

Promise.resolve()
  .then(() => fn.call(this, ...args))
  .then(
    ({ source, map, meta }) => callback(null, source, map, meta),
    error => callback(error)
  );

In this case, it's better to use the second argument of .then here for the error callback instead of using .catch so that if callback throws error, it doesn't get caught and passed to callback again. At least that doesn't seem like the intended use of the API.

return;
}

const source = fs.readFileSync(reason.module.resource).toString();
Copy link
Member

Choose a reason for hiding this comment

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

Better to do fs.readFileSync(reason.module.resource, 'utf8'); instead of .toString(), though not sure if webpack's memory fs supports it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It supports it, but is there any actual reason to change it?

}

function transpile(source: string, map: any, filename: string) {
const file = new babel.File(
Copy link
Member

Choose a reason for hiding this comment

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

What happens if the user doesn't have .babelrc file at all?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It uses normal .babelrc/package.json/.babelrc.js resulution, so if user don't have a babel config it will just assume that the code is standard ES2015 without any experimental features.

As for inlining config in babel-loader, if it's possible to get the options from it through webpack, I do that, otherwise, the loader will accept inlined babel config.

filename,
sourceMaps: true,
inputSourceMap: map,
presets: [require.resolve('../../babel.js')],
Copy link
Member

@satya164 satya164 Dec 14, 2017

Choose a reason for hiding this comment

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

We should be able to pass options to our babel preset via the loader options

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, shouldn't it be presets: [require.resolve('../../babel.js'), loaderOptions] ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why? There are other options for babel that you might be interested in. Limiting it only to presets doesn't sound good. What if you want to pass plugins?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Still, if you want to pass options to linaria preset it would look like this:

{
  loader: 'linaria/loader',
  options: {
    presets: [['linaria/babel', { /* options */ }]]
  }
}

Copy link
Member

@satya164 satya164 Dec 14, 2017

Choose a reason for hiding this comment

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

Why would we want to allow passing arbitrary presets and plugins? It's linaria-loader. People can use babel-loader for other babel stuff. Otherwise it'll just be a half-baked babel-loader with linaria preset included by default.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But maybe you don't want all of out plugins to be applied? Only preval-extract?

Copy link
Member

Choose a reason for hiding this comment

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

Not sure what's the usecase, but it should be an item in the options object if it needs to be exposed instead of overriding all plugins/presets.

Copy link
Member

@satya164 satya164 left a comment

Choose a reason for hiding this comment

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

Now that we have the loader, I think it's worth adding to the README that you don't need to be using Babel to use Linaria if you use the webpack loader.

@@ -1,5 +1,9 @@
# `linaria/babel` preset

__If you use Webpack__, we highly recommend to add `linaria/loader` to your JS rule in Webpack config. It supports the same options as the preset. For more information go [here](./BUNDLERS_INTEGRATION.md#loader).
Copy link
Member

Choose a reason for hiding this comment

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

I think the term JS rule is confusing. I'd remove it since we have clear instructions for this anyway.

Add to avoid issues to the end of the first line.

Change For more information go [here] to [See here] for instructions on configuring the loader.

@@ -2,6 +2,54 @@

## webpack

### Loader

For the best user experience while working with Linaria we recommend to use our custom loader.
Copy link
Member

Choose a reason for hiding this comment

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

For the best developer experience with Linaria, we recommend to use our webpack loader`


For the best user experience while working with Linaria we recommend to use our custom loader.

Just add it to a JS rule after `babel-loader` in webpack config:
Copy link
Member

Choose a reason for hiding this comment

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

In your webpack config, you'll need to add `linaria/loader` to run Linaria on `.js` files:

},
```

It serves the following purposes:
Copy link
Member

Choose a reason for hiding this comment

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

I think it's unnecessary to mention these since these were bugs/limitations.

@zamotany zamotany merged commit 4efecba into master Dec 14, 2017
@zamotany zamotany deleted the webpack-loader branch December 14, 2017 12:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants