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

How to use less and inject / extract #24

Closed
D1no opened this issue Oct 11, 2017 · 7 comments
Closed

How to use less and inject / extract #24

D1no opened this issue Oct 11, 2017 · 7 comments

Comments

@D1no
Copy link
Contributor

D1no commented Oct 11, 2017

Not sure how the parsing of less files and injection into the bundle works.

@D1no
Copy link
Contributor Author

D1no commented Oct 11, 2017

This works with yarn dev but does not run on yarn build (unrecognised token error for less imports)

const ExtractTextPlugin = require("extract-text-webpack-plugin");

// (...)

  Html: class CustomHtml extends Component {

// (...)
            <link href="index.css" rel="stylesheet" />
            {styleTags}

// (...)

  },
webpack: (webpackConfigurator, { dev }) => {

    webpackConfigurator.merge({
      module: {
        rules: [
          {
            test: /\.less$/,
            use: ExtractTextPlugin.extract({
              fallback: 'style-loader',
              use: [
                { loader: "css-loader" },
                {
                  loader: "less-loader",
                  options: {
                    paths: [
                      path.resolve(__dirname, "node_modules")
                    ]
                  }
                }
              ]
            })
          }
        ]
      },
      plugins: [
        new ExtractTextPlugin({
          filename: 'index.css',
          disable: false,
          allChunks: true
        })
      ]
    })

@derekperkins derekperkins changed the title How to use less and incject / extract How to use less and inject / extract Oct 11, 2017
@D1no
Copy link
Contributor Author

D1no commented Oct 13, 2017

Any Idea? I would like to get this problem out of the way. And I know - I love styled-components as well. But many UI libraries, such as ant design, still require css/less Files. And it would be nice to be able to handle them properly.

@D1no
Copy link
Contributor Author

D1no commented Oct 13, 2017

From the video, I really just want to make sure this is really a 48h Problem 😅

@D1no
Copy link
Contributor Author

D1no commented Oct 16, 2017

This also solves
#40
#36

So after investigating whats going on with the unsatisfied loader problems of react-static, I figured out that the two stage process (first Babel creating the Webpack configuration, than Webpack executing the compile) leads to a poluted AST for the babel compiler, which, for example, finds all of the sudden import "xyz.less" in its AST and does not know how to handle them. The same applies to non-js extension like images or plain css files.

The solution is to explicitly tell Babel to not handle those extensions, so they are skipped and consumed by webpack in a later stage.

yarn add --dev babel-register

add this code to the beginning of the static.config.js file

// This extends the node env require stetement with babel config literals
require("babel-register");

// Don't pre-process these extensions
const ignoreExtInBabelPreProcess = [
  '.css',
  '.scss',
  '.sass',
  '.pcss',
  '.stylus',
  '.styl',
  '.less',
  '.sss',
  '.gif',
  '.jpeg',
  '.jpg',
  '.png',
  '.svg',
  '.mp4',
  '.webm',
  '.ogv',
  '.ts',
  '.tsx',
];

// Collect all preview handler incase we want to change this later via
// registerBabelIgnoreExtHandlers([".someOtherExt"]);
let prevExtensionHandler = {};

// Our null handler to be assigned to required/imported files in the code
// that meets our ignore list
function newNullReturnHandler() { }

// Necessary to change extensions later down the road
function rewind() {
  for (const ext in prevExtensionHandler) {
    if (prevExtensionHandler[ext] === undefined) {
      delete require.extensions[ext]
    } else {
      require.extensions[ext] = prevExtensionHandler[ext]
    }
  }

  prevExtensionHandler = {}
}

// Registering the handlers
function registerBabelIgnoreExtHandlers(extensions = ignoreExtInBabelPreProcess, handler = newNullReturnHandler) {
  rewind();

  for (const ext of extensions) {
    prevExtensionHandler[ext] = require.extensions[ext];
    require.extensions[ext] = handler
  }
}

// Register the handlers as by the default list above or use
// registerBabelIgnoreExtHandlers([".someOtherExt", ".someExt"]);
registerBabelIgnoreExtHandlers();

I was looking into how to include this into the distribution. The problem is, babel-register needs to be called in the context of the app code and not from the the context of the package. I have it written now, so that it is applicable. But did not have the time to invest further time into a PR yet. But our less workflow works now with ant design.

@tannerlinsley
Copy link
Contributor

This is now possible with the latest version, and a bit of work. Please upgrade both global and local packages to version 2.0.0

You'll want to reference the withCssLoader from react-static's plugins and note its usage in the following static.config.js file:

import axios from 'axios'
//
import withCss from 'react-static/lib/plugins/withCssLoader'
import withFiles from 'react-static/lib/plugins/withFileLoader'

export default {
  getSiteProps: () => ({
    title: 'React Static',
  }),
  getRoutes: async () => {
    const { data: posts } = await axios.get('https://jsonplaceholder.typicode.com/posts')
    return [
      {
        path: '/',
        component: 'src/containers/Home',
      },
      {
        path: '/about',
        component: 'src/containers/About',
      },
      {
        path: '/blog',
        component: 'src/containers/Blog',
        getProps: () => ({
          posts,
        }),
        children: posts.map(post => ({
          path: `/post/${post.id}`,
          component: 'src/containers/Post',
          getProps: () => ({
            post,
          }),
        })),
      },
      {
        is404: true,
        component: 'src/containers/404',
      },
    ]
  },
  webpack: [withCss, withFiles],
}

You'll obviously need to add loaders to get this to work, but it is no longer a bug, or lack of feature, and instead an implementation detail. We will try and get an example up soon on how to use Less.

@djnicholson
Copy link

`'react-static/lib/plugins/withFileLoader' no longer exists, did it get replaced with a plugin package?

@SleeplessByte
Copy link
Member

@djnicholson are you looking for this?

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

No branches or pull requests

4 participants