Skip to content

What's the correct way to use npm distributed css? #1053

@Shuumatsu

Description

@Shuumatsu

I'm new to lit-element and I'm trying to implement a custom element for rendering math equations for my website using Katex.
To properly render the equations, I need to import the css&font files provided by Katex.
I have the following codes,

import styles from '!!raw-loader!katex/dist/katex.css' 
// Some font files are imported inside the katex.css files, so this line won't work. (The font files won't be processed by webpack.
import 'katex/dist/katex.css' 
//So I add `import 'katex/dist/katex.css'` as well.

...
    static get styles() {
        return [unsafeCSS(styles)]
    }
...

it works but there are still some problems.

  1. the same code will be imported twice
  2. the font import statement inside unsafeCSS(styles) will be executed, but the path is not correct.

So my goal is two: 1. let weback recursively process all styles related files 2. get the CSS string so I can use it with unsafeCSS(styles)


below are the complete code and my webpack config.

import { LitElement, html, property, customElement, unsafeCSS } from 'lit-element'
import { unsafeHTML } from 'lit-html/directives/unsafe-html.js'
import { styleMap } from 'lit-html/directives/style-map'
import katex from 'katex'
import 'katex/dist/katex.css'
import styles from '!!raw-loader!katex/dist/katex.css'

@customElement('mathjax-panel')
export class MathjaxPanel extends LitElement {
    @property() rendered = ''
    @property({ reflect: true }) block = false

    static get styles() {
        return [unsafeCSS(styles)]
    }

    slotchange = (event: Event) => {
        const slot = this.shadowRoot?.querySelector('slot')
        const math = slot?.assignedNodes()[0].textContent
        if (math) {
            try {
                this.rendered = katex.renderToString(math, { displayMode: this.block, output: 'html' })
            } catch (error) {
                console.error(`failed to render math equation: ${math}`)
            }
        }
    }

    render() {
        const rstyle = this.rendered ? '' : styleMap({ display: 'none' })
        const pstyle = this.rendered ? styleMap({ display: 'none' }) : ''
        if (this.block) {
            return html`
                <div style=${rstyle}>${unsafeHTML(this.rendered)}</div>
                <pre style=${pstyle}><div><slot @slotchange=${this.slotchange}></slot></div></pre>
            `
        }
        return html`
            <span style=${rstyle}>${unsafeHTML(this.rendered)}</span>
            <pre style=${pstyle}><span><slot @slotchange=${this.slotchange}></slot></span></pre>
        `
    }
}

webpack.common.js:

const paths = require('./paths')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const configs = {
    entry: './src/app.ts',
    devtool: 'inline-source-map',
    output: {
        publicPath: '/web/static',
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: 'ts-loader',
                exclude: /node_modules/,
            },

            {
                test: /\.(png|svg|jpg|gif)$/,
                use: ['file-loader'],
            },
            {
                test: /\.(woff|woff2|eot|ttf|otf)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: '[name].[ext]',
                            outputPath: 'fonts/'
                        }
                    }
                ]
            },
        ],
    },
    resolve: {
        extensions: ['.tsx', '.ts', '.js'],
    },
    output: {
        filename: '[name].bundle.js',
        path: paths.pages_dir,
    },
}

module.exports = configs

webpack.dev.js:

const { merge } = require('webpack-merge');
const common = require('./webpack.common.js')

module.exports = merge(common, {
    mode: 'development', devtool: 'inline-source-map', module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
            },
        ],
    },
})

webpack.prod.js:

const { merge } = require('webpack-merge');
const common = require('./webpack.common.js')
const TerserJSPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = merge(common, {
    mode: 'production', devtool: 'source-map', module: {
        rules: [
            {
                test: /\.css$/i,
                use: [MiniCssExtractPlugin.loader, 'css-loader'],
            },
        ],
    },
    plugins: [new MiniCssExtractPlugin()],
    optimization: {
        minimize: true,
        minimizer: [new TerserJSPlugin({}), new CssMinimizerPlugin()],
    },
})

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions