Coder Social home page Coder Social logo

webpack-bem-loader's Introduction

Webpack BEM loader

Webpack loader for bem-react-core

BEM entities auto resolver for custom import strings:

import Block from 'b:block';
import Block from 'b:block m:modName';
import Block from 'b:block m:modName=modVal1|modVal2';
import BlockElem from 'b:block e:elem';
import BlockElem from 'b:block e:elem m:modName';
import BlockElem from 'b:block e:elem m:modName=modVal1|modVal2';

Install

npm i -D webpack-bem-loader

Usage

In your webpack.config.js.

Webpack 1

  // setting for bem-loader
  bemLoader: {
    naming: 'react',
    levels: ['./pathToBlocks'],
    // OR:
    // levels: {
    //     './pathToBlocks': {
    //         default: true,
    //         scheme: 'nested',
    //         naming: 'origin'
    //     }
    // },
    techs: ['js', 'css'],
    techMap: {
        js : ['react.js']
    },
    langs: ['ru', 'en']
  },

Webpack 2

// setting for bem-loader
module: {
    rules: [
        {
            test : /\.react\.js$/,
            loader: 'webpack-bem-loader',
            options: {
                naming: 'react',
                levels: ['./pathToBlocks'],
                // OR:
                // levels: {
                //     './pathToBlocks': {
                //         default: true,
                //         scheme: 'nested',
                //         naming: 'origin'
                //     }
                // },
                techs: ['js', 'css'],
                techMap: {
                    js : ['react.js']
                },
                langs: ['ru', 'en']
            }
        }
    ]
}

Options

  • levels : Required option — paths to components declarations
  • naming: bem-naming overrides naming
  • techs : list of techs extensions for require in runtime, ['js'] by default. First tech will be default export
  • techMap : mapping of techs to extensions. Example: { 'js' : ['react.js', 'react.ts', 'react.es'], 'css' : ['post.css'] }
  • langs : list of langs in which resloves '.i18n' tech
  • generators : customization of code generators by tech. The function when it is provided receive one argument: files with signature Array<String>. This is the list of files of the specified technology, got from current import. Examples: { js : null } or { js: (files) => files.map(file => `require('${file.path}')`).join(',\n') }. Each generator must return String. Check ./generators for examples.

    i18n

    .i18n - represent special technology that provides the opportunity to localize components.

    On file system:

    blocks/Attach/
    ├── Attach.react.js
    ├── Attach.i18n
    │   ├── en.js
    │   ├── ru.js
    │   └── tr.js
    └── Attach.spec.js
    

    en.js, ru.js and tr.js are keysets and should be common.js modules.

    $ cat blocks/Attach/Attach.i18n/tr.js
    module.exports = {
        "Attach": {
            "button-text": "Dosya seç",
            "no-file": "dosya seçilmedi"
        }
    };

    inside Attach.js:

    import i18n from `b:Attach t:i18n`
    
    console.log(i18n('button-text')) // → Dosya seç

    webpack-bem-loader transpiles such code to

    var i18n = (function() {
        var core = require('/absolute-path-to/webpack-bem-loader/generators/i18n/core');
    
        if (process.env.BEM_LANG === 'ru') {
            return core().decl(require('../Attach.i18n/ru'))('Attach')
        }
    
        if (process.env.BEM_LANG === 'en') {
            return core().decl(require('../Attach.i18n/en'))('Attach')
        }
    
        if (process.env.BEM_LANG === 'tr') {
            return core().decl(require('../Attach.i18n/tr'))('Attach')
        }
    })();
    
    console.log(i18n('button-text')) // → Dosya seç

    process.env.BEM_LANG is need to be defined. ru, en and tr are taken from langs option.

    License MPL-2.0

webpack-bem-loader's People

Contributors

amje avatar awinogradov avatar golyshevd avatar koreil avatar nikita-ezhkov avatar poalrom avatar remnev avatar tsufiev avatar veged avatar yar-usenko avatar yarastqt avatar yeti-or avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

webpack-bem-loader's Issues

Real life purpose of emitting errors about BEM module

For now we have code for emitting errors about non existent BEM modules.

webpack-bem-loader/index.js

Lines 139 to 144 in e9c1640

Object.keys(existsEntities).forEach(fileId => {
// check if entity has no tech to resolve
existsEntities[fileId] || errEntities[fileId].forEach(file => {
this.emitError(`BEM module not found: ${file.path}`);
});
});

In real projects it looks like infinite noise that does not help.
At the same time emitError requires a special as an argument as passing there a string generates Critical errors inside Webpack itself.

ERROR in ./blocks/block-a/block-a.react.js
(Emitted value instead of an instance of Error) BEM module not found: ../block-b/block-b.css
 @ ./blocks/block-a/block-a.examples/index.react.js 21:26-59 21:71-104

Actually, there are 2 cases that we should fix here:

  • Create an error object instead of string to pass it in emitError
  • Reduce count of errors (to a zero if possible)

update @bem dependencies

@bem -> @bem/sdk

    "@bem/cell": "^0.2.6",
    "@bem/entity-name": "^1.5.0",
    "@bem/fs-scheme": "^2.1.0",
    "@bem/import-notation": "^1.1.2",
    "@bem/naming": "^2.0.0-6",

What's naming and levels?

Link to 'naming' leads to almost empty page.

Also RFC for

                // levels: {
                //     './pathToBlocks': {
                //         default: true,
                //         scheme: 'nested',
                //         naming: 'origin'
                //     }
                // },

Default? Scheme? Naming?

Thank you.

tech options works incorrectly for different techs on same levels

For example, we have such options:

                    options : {
                        levels : [
                            'project'
                        ],
                        techmap : {
                            js : ['ts', 'js']
                        }
                    }

and we have two files button.js and button.ts both on level project
first on level common second on desktop
right now we get:

   [(
require('./project/button/button.ts')).applyDecls()
    ),(
    (
require('./project/button/button.js')).applyDecls()
    )][0]

we will get component that we want (button.ts) but we will applyDecls for button.js
it's wrong. In such case, we should use only one — js : ['ts', 'js'] the first one from the array of techMap.

Add AppVeyor for testing on Win

It seems there are some troubles with path resolving on Windows
import BPage from 'b:b-page';

It will eat Win slashes and path to this block won't be resolved.

Module not found: Can't resolve './common.blocksAppRouterAppRouter.js' on windows

Failed to compile.

Error in ./src/index.js
Module not found: Can't resolve './common.blocksAppRouterAppRouter.js' in 'c:\work\<PROJECT_NAME>\src'

 @ multi ./~/react-dev-utils/webpackHotDevClient.js ./~/bem-react-scripts/config/polyfills.js ./src/index.js

import AppRouter from 'b:AppRouter';

It seems that b:blah-blah import missing slash on Windows.

BEM.i18n callback for wrapping Components

Right now we have <i18n:param> for better localization.

and we use it like this:

{
 "myKey": "Some text <i18n:param>someParam</i18n:param>"
}

an in code:

import i18n from 'b:awesomeB t:i18n';

<input value={ i18n('mykey',  { someParam: 'wow' }) } >;

And it's cool
but what to do if we want to localize string with Component inside, or .

like:

import i18n from 'b:awesomeB t:i18n';

const button = (text) => (<button>{ text }</button>);

<span>{ i18n('myKeyInsideButton', { someParam: button }) }</span>

What syntax in keysets should we use?

my proposal:

{
"myKey": "... and then button: <i18n:wrap name='someParam'>Localized Btn-text</i18n:wrap>"
}

@veged any suggestions?

Process es6 modules import

Right now we work only with require:

if(!(
  node.type === 'CallExpression' &&
  node.callee.type === 'Identifier' &&
  node.callee.name === 'require' &&
  Object(node.arguments[0]).value
)) return;

we could process imports too.

tech options works incorrectly for different techs on different levels

For example, we have such options:

                    options : {
                        levels : [
                            'common',
                            'project'
                        ],
                        techmap : {
                            js : ['ts', 'js']
                        }
                    }

and we have two files button.js and button.ts
first on level common second on project
right now we get:

   [(
require('./common/button/button.ts')).applyDecls()
    ),(
    (
require('./project/button/button.js')).applyDecls()
    )][0]

so we get only common button
but we want:

   [(
require('./common/button/button.ts'),
require('./project/button/button.js')).applyDecls()
    )][0]

to get full component

Breaking change of styles' loading order @ 0.6.0

Hi guys.

Let's say there is a following case:

├─ blocks
│ └─ Example
│ │ ├─ _mod1
│ │ │ └─ Example_mod1.css  /* styles #1 */
│ │ ├─ _mod2
│ │ │ └─ Example_mod2.css  /* styles #2 */
│ │ ├─ Example.css         /* styles #0 */
│ │ └─ Example.js
└─ app.js

/*   Example.js   */
...
import 'm:mod1';
export default decl({
  block: 'Example'
});

/*   app.js   */
...
import Example from 'b:Example m:mod2';
...

where mod1 is pretty lightweight and widely used (e.g. some disabled state with one-two loc), thus it's just easier to include it as a base block functionality (but still keep in a separate folder for clarity). Obviously, as mod1 overrides block's base styles, its css should be loaded after the main one.

With loader version <=0.5.1 loading order of styles was predictable & ok: 0 -> 2 -> 1.
But with 0.6.0 now it is 1 -> 0 -> 2 and totally breaks existing logic, described above.

Loose block context

If you try to import element in block import 'e:Elem' from block's modifier you'll see this:

Module build failed: Error: This is not valid BEM entity: the field `block` is undefined.

TypeScript support

Now it works only by this way:

import * as Search from 'b:Search';

console.log(Search);

Because we transpile it to:

const Search = ((
(__webpack_require__(2).default || __webpack_require__(2)).applyDecls()
));

// ts use it like this
console.log(Search);

But! If we want use default export only:

import Search from 'b:Search';

console.log(Search);
const Search = ((
(__webpack_require__(2).default || __webpack_require__(2)).applyDecls()
));

// ts use it like this
console.log(Search.default); // .default -> undefined

We need to transpile it like this:

const Search = {
  default: ((
    (__webpack_require__(2).default || __webpack_require__(2)).applyDecls()
  ))
};

Rename to bem-loader

So, I can republish (bem-loader)[https://www.npmjs.com/package/bem-loader] with the different name, and we'll use bem-loader.bem option in webpack.config instead bemLoader and bem in the list of loaders instead of webpack-bem.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.