-
Notifications
You must be signed in to change notification settings - Fork 414
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
Webpack loader #186
Conversation
Codecov Report
@@ 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.
|
@@ -0,0 +1 @@ | |||
module.exports = require('./build/tools/webpack-loader').default; |
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.
We want to publish this file, please add it to "files" in package.json
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.
Done
website/webpack.config.js
Outdated
@@ -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' }], |
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.
Let's enable cache for babel-loader
here to make sure we always test against it
src/tools/webpack-loader.js
Outdated
}; | ||
} | ||
|
||
function makeLoaderAdapter(fn) { |
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.
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.
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 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)( |
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.
Probably better to use the async babel.transformFromAst
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.
There is no async version of transformFromAst
in Babel 6.
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.
Yes, I meant always use babel.transformFromAst
, sync or async. You were handling promises anyway.
src/tools/webpack-loader.js
Outdated
} | ||
|
||
function makeLoaderAdapter(fn) { | ||
function loaderAdapter(...args: any[]) { |
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.
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.
src/tools/webpack-loader.js
Outdated
return; | ||
} | ||
|
||
const source = fs.readFileSync(reason.module.resource).toString(); |
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.
Better to do fs.readFileSync(reason.module.resource, 'utf8');
instead of .toString()
, though not sure if webpack's memory fs supports it.
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.
It supports it, but is there any actual reason to change it?
src/tools/webpack-loader.js
Outdated
} | ||
|
||
function transpile(source: string, map: any, filename: string) { | ||
const file = new babel.File( |
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.
What happens if the user doesn't have .babelrc
file at all?
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.
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.
src/tools/webpack-loader.js
Outdated
filename, | ||
sourceMaps: true, | ||
inputSourceMap: map, | ||
presets: [require.resolve('../../babel.js')], |
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.
We should be able to pass options to our babel preset via the loader options
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.
Done
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.
Hmm, shouldn't it be presets: [require.resolve('../../babel.js'), loaderOptions]
?
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.
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
?
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.
Still, if you want to pass options to linaria preset it would look like this:
{
loader: 'linaria/loader',
options: {
presets: [['linaria/babel', { /* options */ }]]
}
}
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.
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.
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.
But maybe you don't want all of out plugins to be applied? Only preval-extract
?
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.
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.
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.
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.
docs/BABEL_PRESET.md
Outdated
@@ -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). |
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 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.
docs/BUNDLERS_INTEGRATION.md
Outdated
@@ -2,6 +2,54 @@ | |||
|
|||
## webpack | |||
|
|||
### Loader | |||
|
|||
For the best user experience while working with Linaria we recommend to use our custom loader. |
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.
For the best developer experience with Linaria, we recommend to use our webpack loader`
docs/BUNDLERS_INTEGRATION.md
Outdated
|
||
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: |
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.
In your webpack config, you'll need to add `linaria/loader` to run Linaria on `.js` files:
docs/BUNDLERS_INTEGRATION.md
Outdated
}, | ||
``` | ||
|
||
It serves the following purposes: |
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 it's unnecessary to mention these since these were bugs/limitations.
Fixes #73, #169
Documentation is missing, but I'll make it once the code will be done.
So the JS rule looks like this:
Then while testing on website:
theme.js
rebuilds CSS so HMR updates styles.linaria-cache
doesn't break anything