UNPKG

modulerizr

Version:

Integrate a powerful, component based architecture to your legacy project in just a few steps

244 lines (206 loc) 10.8 kB
# Modulerizr [![npm version](https://img.shields.io/npm/v/modulerizr.svg)](https://www.npmjs.com/package/modulerizr) [![npm downloads](https://img.shields.io/npm/dt/modulerizr.svg)](https://www.npmjs.com/package/modulerizr) [![npm downloads](https://img.shields.io/github/license/mashape/apistatus.svg)](https://www.npmjs.com/package/modulerizr) Quick Links - [Main page](https://github.com/bassdman/modulerizr/) - [ModulerizrWebpackPlugin](https://www.npmjs.com/package/modulerizr-webpack-plugin) ## Create your own Plugins A Modulerizr-Plugin is just a webpack-plugin. That means, a modulerizr-plugin is a webpack-plugin with some extra features. And every webpack plugin also works with modulerizr. To learn how to create a webpack plugin, look up the [webpack-documentation](https://webpack.js.org/contribute/writing-a-plugin/). ### Build up a custom Plugin Let's imagine, you need some data of star wars characters available in every of your components. Let's create a star-wars-plugin for it. You find the sources of the following examples here: https://github.com/bassdman/modulerizr/tree/master/samples/starwarsplugin . #### Create the basics A webpack plugin is a class with an apply function. Let's create it for our star-wars-plugin. File: StarWarsPlugin.js ```javascript class StarWarsPlugin { constructor(pluginconfig = {}) { } apply(compiler) { console.log('StarWarsPlugin is executed') } } exports.StarWarsPlugin = StarWarsPlugin; ``` We can embedd this plugin in our webpack or modulerizr-config: Webpack: ```javascript const { ModulerizrWebpackPlugin } = require('modulerizr-webpack-plugin'); const { StarWarsPlugin } = require('./StarWarsPlugin'); const path = require('path'); module.exports = { output: { path: 'path/to/dest' }, entry: './anEntryFile.js', plugins: [ new ModulerizrWebpackPlugin({ // your configuration here }), new StarWarsPlugin() ] }; ``` Modulerizr: ``` javascript const { modulerizr } = require("modulerizr"); const { StarWarsPlugin } = require('./StarWarsPlugin'); modulerizr.run({ ... plugins: [new StarWarsPlugin()], //other configuration here ... }) ``` When we execute it, we will already have a log "Starwars plugin is executed". Yippeeee :) #### Extend some hooks Webpack uses hooks to modify the webpack context. There are default webpack-hooks that can be used, with modulerizr you have some extra hooks. Look up here for the [standard-webpack-hooks](https://webpack.js.org/api/compiler-hooks/). With the [Modulerizr-Hooks](#modulerizr-hooks) you have the chance to modify the files in a simple way with jquery-syntax. Let's use a custom modulerizr-hook. ```javascript class StarWarsPlugin { constructor(pluginconfig = {}) { } apply(compiler) { // We want the star wars data to be added on top of the rendered Data. So we use the "modulerizrFileRendered"-Hook compiler.hooks.modulerizrFileRendered.tap('StarWarsPlugin', ($el, srcFile, context) => { console.log('here we have to add our code'); }); } } exports.StarWarsPlugin = StarWarsPlugin; ``` If you are familiar with jquery, you can just start modifying the html using the $el-Parameter. In this hook it is the root-Element of the src-file. With it you can modify the html, get some Attributes, select subtags,.. See the documentation of [cheerio](https://github.com/cheeriojs/cheerio) (=jquery-library on server side) for details. #### Modify HTML Let's add a script to each source-file that logs "Let's add some starwars-data". We want this script tag as last tag of the head ```javascript class StarWarsPlugin { constructor(pluginconfig = {}) { } apply(compiler) { // We want the star wars data to be added on top of the rendered Data. So we use the "modulerizrFileRendered"-Hook compiler.hooks.modulerizrFileRendered.tap('StarWarsPlugin', ($, srcFile, context) => { const $head = $('head'); $head.append("<script>console.log('Let's add some starwars-data');</script>"); // or in short: $('head').append("<script>console.log('Let's add some starwars-data');</script>"); }); } } exports.StarWarsPlugin = StarWarsPlugin; ``` #### Get StarWars-Characters Luckily there is the [Swapi](https://swapi.co/) to get all relevant star wars data via api. We want to fetch all characters, this can be done by the url https://swapi.co/api/people/ . ```javascript const fetch = require('node-fetch'); class StarWarsPlugin { constructor(pluginconfig = {}) { } apply(compiler) { //We want the starwars-data to be fetched just on beginning - so we use the modulerizrInit-Hook compiler.hooks.modulerizrInit.tapPromise('StarWarsPlugin', async context => { const starwarsCharacters = await fetch('https://swapi.co/api/people/').then(res => res.json()) context.starwarsCharacters = starwarsCharacters; }); // We want the star wars data to be rendered in each file. So we use the "modulerizrFileRendered"-Hook compiler.hooks.modulerizrFileRendered.tap('StarWarsPlugin', ($, srcFile, context) => { const $head = $('head'); const starwarsDataAsString = JSON.stringify(context.starwarsCharacters.results); $head.append(`<script>var starwarsdata = ${starwarsDataAsString};</script>`); }); } } exports.StarWarsPlugin = StarWarsPlugin; ``` That's it. Now we have added star wars data to every src-file. Of course this shouldn't be a real usecase. But it shows how to create new Plugins. The result looks like this: ```html <html ><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Starwars-plugin - sourcefile 1 </title> <script>var starwarsdata = [{"name":"Luke Skywalker","height":"172","mass":"77","hair_color":"blond","skin_color":"fair","eye_color":"blue","birth_year":"19BBY","gender":"male","homeworld":"https://swapi.co/api/planets/1/","films":["https://swapi.co/api/films/2/","https://swapi.co/api/films/6/","https://swapi.co/api/films/3/","https://swapi.co/api/films/1/","https://swapi.co/api/films/7/"],"species":["https://swapi.co/api/species/1/"],"vehicles":["https://swapi.co/api/vehicles/14/","https://swapi.co/api/vehicles/30/"],"starships":["https://swapi.co/api/starships/12/","https://swapi.co/api/starships/22/"],"created":"2014-12-09T13:50:51.644000Z","edited":"2014-12-20T21:17:56.891000Z","url":"https://swapi.co/api/people/1/"},...];</script></head> <body> Now we can use the server data from the api. </body></html> ``` ### Hooks There are some specific modulerizr-Hooks. They are executed in the following order: - __modulerizrInit__ (1x) - foreach component-file (1..m) - __modulerizrComponentInitialized__ (component 1); - __modulerizrComponentInitialized__ (component 2); - ... - __modulerizrComponentInitialized__ (component m); - foreach src-file (1..n) - __modulerizrPreRenderFile__ (srcfile 1) - __modulerizrFileRendered__ (srcfile 1) - __modulerizrFileFinished__ (srcfile 1) - ... - __modulerizrPreRenderFile__ (srcfile n) - __modulerizrFileRendered__ (srcfile n) - __modulerizrFileFinished__ (srcfile n) - __modulerizrFinished__ (1x) All Hooks are [AsyncSeriesHooks](https://webpack.js.org/contribute/writing-a-plugin/#asynchronous-hooks), so they can handle synchronous, asynchronous and promise-based functions. #### modulerizrInit Executed Once, good for initialisation of data or initializing your own hooks ```javascript compiler.hooks.modulerizrInit.tapPromise('PluginName', (context) => { // context: Every plugin can read from / modify this global context }); ``` #### modulerizrComponentInitialized Executed for each found Component once; good to modify components before rendering ```javascript compiler.hooks.modulerizrComponentInitialized.tapPromise('PluginName', ($component,component,context) => { // $component: jquery-object of the current component // component: all data corresponding to the current component // context: Every plugin can read from / modify this global context }); ``` #### modulerizrPreRenderFile Is executed for each src-file once, before the components are rendered. Good to modify the html before rendering ```javascript compiler.hooks.modulerizrPreRenderFile.tapPromise('PluginName', ($srcfile,srcfile,context) => { // $srcfile: jquery-object of the current sourcefile // srcfile: all data corresponding to the current srcfile // context: Every plugin can read from / modify this global context }); ``` #### modulerizrFileRendered Executed for each src-file once, after the components are rendered. Good to do html-manipulations on the rendered file. If modifications on already rendered components are needed, you can traverse through the attribute "data-compoennt". ```javascript compiler.hooks.modulerizrFileRendered.tapPromise('PluginName', ($srcfile,srcfile,context) => { // $srcfile: jquery-object of the current sourcefile // srcfile: all data corresponding to the current srcfile // context: Every plugin can read from / modify this global context }); ``` #### modulerizrFileFinished Executed for each src-file once, after hook _modulerizrFileRendered_ - good for cleanup. For example removing unnecessary tags / files of the modularisation process. ```javascript compiler.hooks.modulerizrFileFinished.tapPromise('PluginName', ($srcfile,srcfile,context) => { // $srcfile: jquery-object of the current sourcefile // srcfile: all data corresponding to the current srcfile // context: Every plugin can read from / modify this context }); ``` #### modulerizrFinished Executed after all src-files are finished. The files are still not created. It is executed after the last step of the [beforeEmit-Hook of the HtmlWebpackPlugin](https://github.com/jantimon/html-webpack-plugin#beforeemit-hook). ```javascript compiler.hooks.modulerizrFinished.tapPromise('PluginName', (context) => { // context: Every plugin can read from / modify this context }); ``` #### context Every hook has a context-object. If you want to add data to other plugins, add this data to the context just by modifying it. You can also add helper functions. Look at [StarWarsPlugin v4 Example](#get-starwars-characters) to see how to get / add data to the context. ## May the force be with you Now you have all knowledge to create a new plugin, my Padawan. Now the force shows you how to write modulerizr-plugins. When I forgot to note sth important, please tell me or [create an issue](https://github.com/bassdman/modulerizr/issues).