Last active
March 14, 2017 20:35
-
-
Save tauren/5aa2483b63c703ecff199e4a927a7329 to your computer and use it in GitHub Desktop.
Neutrino customization script WIP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
// TODO: Upgraded to neutrino@beta (v5). Make sure to upgrade to final release version | |
// which should be available mid March. Here are some links on what has changed and | |
// how to update old config to new: | |
// https://github.com/mozilla-neutrino/neutrino-dev/blob/v5.0.0-beta/docs/upgrading-neutrino.md | |
// https://github.com/mozilla-neutrino/neutrino-dev/pull/86#issue-211140309 | |
const merge = require('deepmerge'); | |
const webpack = require('webpack') | |
const cssnext = require('cssnext') | |
const postcssReporter = require('postcss-reporter') | |
const CSS_LOADER = require.resolve('css-loader'); | |
const STYLE_LOADER = require.resolve('style-loader'); | |
const POSTCSS_LOADER = require.resolve('postcss-loader'); | |
const HTML_LOADER = require.resolve('html-loader'); | |
const RAW_LOADER = require.resolve('raw-loader'); | |
const BABEL_LOADER = require.resolve('babel-loader'); | |
const REACT_MARKDOWN_LOADER = require.resolve('react-markdown-loader'); | |
const componentTemplates = require('./src/templates') | |
const path = require('path') | |
const PATCH_LOADER = require.resolve('./patchReactWebpackLoader'); | |
const SVGSYMBOL_LOADER = require.resolve('./svgSymbolLoader'); | |
module.exports = neutrino => { | |
// ------ Patch ReactDOM to support named <slot> ------ // | |
neutrino.config.module | |
.rule('patch') | |
.test(/HTMLDOMPropertyConfig\.js$/) | |
.use('patch') | |
.loader(PATCH_LOADER) | |
// TODO: Do this only for dev environment, not production | |
// Remove minify plugin | |
neutrino.config.plugins.delete('minify'); | |
// ------ Set publicPath so scripts load on all routes ------ // | |
neutrino.config.output.publicPath('/') | |
// ------ SVG Loading ------ // | |
neutrino.config.module.rules.delete('svg') | |
// Process svg files in src/elements/Icons with custom loader | |
// TODO: Process all other svg files normally | |
neutrino.config.module | |
.rule('svg') | |
.test(/\.svg$/) | |
.include | |
.add(path.resolve(__dirname, 'src/elements/Icons')) | |
.end() | |
.use('babel') | |
.loader(BABEL_LOADER) | |
.options(neutrino.config.module.rule('compile').use('babel').get('options')) | |
.tap(options => merge(options, { | |
plugins: [ | |
["transform-react-jsx", { pragma: "h" }] | |
] | |
})) | |
.end() | |
.use('svgsymbol').loader(SVGSYMBOL_LOADER).end() | |
// ------ CSS Loading, preprocessing, and injection ------ // | |
// Remove rule defined in preset since we will be completely replacing them | |
neutrino.config.module.rules.delete('style') | |
// Process global css files, such as those in src/themes and node_modules | |
neutrino.config.module | |
.rule('style') | |
.test(/\.css$/) | |
.exclude | |
.add(path.resolve(__dirname, 'src/elements')) | |
.add(path.resolve(__dirname, 'src/app')) | |
.end() | |
// Inject string of styles into <style> tag | |
.use('style').loader(STYLE_LOADER).end() | |
// Transform @import, css modules, etc into a string | |
.use('css').loader(CSS_LOADER).end() | |
// Transform loaded css with postcss plugins | |
.use('postcss').loader(POSTCSS_LOADER).end() | |
// Process all css in src/app as CSS Modules | |
neutrino.config.module | |
.rule('style-modules') | |
.test(/\.css$/) | |
.include | |
.add(path.resolve(__dirname, 'src/app')) | |
.end() | |
// Inject string of styles into <style> tag | |
.use('style').loader(STYLE_LOADER).end() | |
// Transform @import, css modules, etc into a string | |
.use('css') | |
.loader('css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]') | |
// NOTE: This should work, but results in `css-loader?{modules:true}`. Probably a css-loader bug. | |
// .loader(CSS_LOADER).options({ modules: true, importLoaders: 1 }) | |
.end() | |
// Transform loaded css with postcss plugins | |
.use('postcss') | |
.loader(POSTCSS_LOADER) | |
// Process all css in src/elements into a raw string to be used within shadow DOM in web components | |
neutrino.config.module | |
.rule('style-elements') | |
.test(/\.css$/) | |
.include | |
.add(path.resolve(__dirname, 'src/elements')) | |
.end() | |
// Transform @import, css modules, etc into a string | |
.use('css') | |
.loader(CSS_LOADER) | |
.end() | |
// Transform loaded css with postcss plugins | |
.use('postcss') | |
.loader(POSTCSS_LOADER) | |
// ------ Update Babel Options ------ // | |
// Add support for class properties | |
neutrino.config.module | |
.rule('compile') | |
.use('babel') | |
.tap(options => merge(options, { | |
plugins: [ | |
'babel-plugin-transform-class-properties' | |
] | |
})) | |
// Set JSX pragma to use `h` instead of `React.createElement` | |
// This is to support JSX syntax via hyperscript in custom elements built with SkateJS | |
// Alternatively, /** @jsx h */ could be added to the top of each custom element source | |
neutrino.config.module | |
.rule('compile-elements') | |
.test(/\.jsx?$/) | |
.include | |
.add(path.resolve(__dirname, 'src/elements')) | |
.end() | |
.use('babel') | |
.loader(BABEL_LOADER) | |
.options(neutrino.config.module.rule('compile').use('babel').get('options')) | |
.tap(options => merge(options, { | |
plugins: [ | |
["transform-react-jsx", { pragma: "h" }] | |
] | |
})) | |
// ------ Markdown Loading ------ // | |
// Make sure markdown files get processed with the compile rule | |
neutrino.config.module.rule('compile').test(/(\.jsx?|\.md)$/) | |
// Convert markdown file into react component tree | |
neutrino.config.module | |
.rule('markdown') | |
.test(/\.md$/) | |
.use('markdown') | |
.loader(REACT_MARKDOWN_LOADER) | |
.options({ | |
templates: componentTemplates.component | |
}) | |
// ------ HOW TO ------ // | |
// Remove minify plugin | |
// neutrino.config.plugins.delete('minify'); | |
// Use config from one node as the config for another | |
// .options(neutrino.config.module.rule('compile').use('babel').get('options')) | |
// Example showing how debug by outputing the config of a chain | |
// console.log(neutrino.config.module.rule('css-components').toConfig()) | |
// console.log(neutrino.config.toConfig()) | |
}; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Add support to ReactDOM v15 for slot attribute | |
* | |
* This makes React allow the `slot` attribute on native DOM elements, | |
* enabling the use of named <slot> tags in custom elements | |
*/ | |
module.exports = function patchReactWebpackLoader(source) { | |
return source.replace(/Properties: {/, 'Properties: {\n slot:0,') | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Convert svg file with symbols into a hash map in jsx format | |
*/ | |
module.exports = function svgSymbolLoader(source) { | |
const regex = /<title>([^<]*)<\/title>\n(<path[^<]*<\/path>)/g | |
let matches | |
let out = `import { h } from 'skatejs'\n | |
export default {\n` | |
while (matches = regex.exec( source )) { | |
out += `'${matches[1]}': ${matches[2]},\n` | |
} | |
out += '}\n' | |
return out | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Description
This neutrino customization is for a project that contains a collection of Custom Elements. The project also contains a react application for users to explore and read the documentation for each custom element. The elements are exported without dependencies on React, etc.
What does it do?
Patch ReactDOM
ReactDOM doesn't support
<slot>
tags which are needed to use Custom Elements (Web Components). The following patches theHTMLDOMPropertyConfig.js
file in the ReactDOM package to add support.Splits SVG file into javascript object
Splits an SVG file containing multiple symbols into a hash map of jsx markup. For instance,
import icons from './icons.svg'
will result inicons
having a value like this:First, it deletes the existing
svg
rule. Objective: do not delete existing rule, only override it for the Icons directoryThen it creates a new
svg
rule to process any svg files in theIcons
element using a custom loader. This uses the same babel config that is used later in the script. Objective: make this more DRY, do not repeat the babel configProcesses CSS in various ways
The CSS loading needs to be handled differently for various parts of this project. This is because the project contains both pure custom elements as well as react components.
style
rule is replaced with a rule that injects global css, such as those in src/themes and node_modulesstyle-modules
rule loads styles for the app's React components as CSS modulesstyle-elements
rule loads css for custom elements into a raw string to be included within element shadow DOMUpdate Babel Options
h
instead ofReact.createElement
only for the custom elementsObjective: make this more DRY, do not repeat the babel config
Compile Markdown files
Markdown files are included with each custom element and are compiled into react components to be displayed as documentation pages.
compile
rule to compile bothjsx?
andmd
files.md
files using the markdown loader