node package manager
Easy sharing. Manage teams and permissions with one click. Create a free org »

webmatrix

Webmatrix: One convention-first web front end development scaffold

This is one scaffold based on webpack and its other middlewares to support proxy localhost request to remote uri(see detail in proxy-table)

The purpose of the project is to help front-end developer focusing on business logic of app, so we provide a set of tools to resolve the problems in most cases.

Introduction

As of customization, the default config(written in) can be fixed or overridden by app's config from js even or yaml.

birth of webmatrix of this project

This project is inspired by vue-cli:template:webpack generated by Vue's official command line tool vue-cli, during developing the webmatrix I found the cooking-cli developed by ElemeFE, it's similar with webmatrix's previous version, but it can be more configurable.

Problem of ElemeFE's cooking-cli:

  • you cannot configure the babel-presets and babel-plugins at your sub project's package.json, instead, you should install it in cooking-cli. that is how webmatrix 0.0.4-alpha did.
  • you must be familiar with the vue-cli:template:webpack
  • it's just for vue ecosystem.

After I joined in the Eleme, I have more spare time to fix the webmatrix's issue, thx to my leader who encourage me find one better tool for web development. : )

Get Started

install wm

by npm

# globally
npm install -g webmatrix

you don't need webmatrix as one devDependency, or why don't you just use webpack?

manually

step to install wm tool:

  • clone the repository by run git clone git@git.oschina.net:ChenLei189/webmatrix.git
  • config the .wm.yaml in 'PATH_TO_wm/webpack/config/.wm/yaml' locally by consulting the file '.wm.yaml.tmpl' in the same directory.
  • run npm link to install wm globally.

(optional) install one app-container

Download developed app-container or develop your own one, put it in path 'PATH_TO_wm/app-container', then you can use the 'container' linked to the appContainer directory as require-sensive prefix. In your app(you can see detail about app later), for instance, require('container/app.js') equals to require('PATH_TO_wm/app-containers/vue-apps/app.js')

create an web app

after you install webmatrix globally

  • change directory to 'PATH_TO_wm/apps'
  • wm init my_app --type=web
  • cd my_app
  • wmweb dev -a my_app

NOTICE now I just provide one web type project initilizor, I plan to add support to type below:

  • electron
  • nodejs need babel-compiled.
  • golang with front-end SPA.

Config Your App

defaultConfig

...

config from APP_DIRECTORY/webpack/config/.wm.yaml

...

Notice

babel and eslint's plugin/presets

never install plugins and presets of babel, eslint, etc. in App's directory, they maybe import the whole babel when being installed. e.g. babel-preset-react, eslint-plugin-react

related: webpack-loader

webpack loaders maybe require to be installed in the same root project directory path with the webpack. that doesn't make sense, but the babel would find them in the app's direcotry if there have been babel-loader in app's node_modules. So avoid add babel and its other presets/plugins as app's dependencies.

return babel/babel-loader, eslint/eslint-plugin/eslint-extends to app's dependencies.

start from webmatrix@>==0.0.5-alpha

after webmatrix@>=0.0.5-alpha, the babel presets and plugins can be installed and loaded from container or app directory.

At start of this project, I installed some babel-plugins/babel-presets and eslint-plugins/eslint-extends as webmatrix's devDependencies, then webpack in webmatrix's node_modules can find them, but with the increasing of apps' driven by webmatrix, I found I cannot specify the plugins/presets and extends of babel/eslint for one specific app's project directory, for a instance, I want use babel-plugin-transform-vue-jsx in project A but I don't need it in another project B, I should't install it as webmatrix devDependicies. This problem can be resolved by webmatrix's container mechanism, but in the most cases, you just dont want use one plugin/preset provided by webmtrix.

why I must install them in webmatrix? Because I must let webpack find them, so they must can be found in the require.main.paths after webpack start one process. But you don't need all of them sometimes, so, I determine change the mechanism for shared webpack of webmatrix: make one symbolic link from 'webmatrix' directory in app/app-container's node_modules directory to the real webpack directory, so we can make webpack 'exists' in the app/app-container's node_modules rather than just foundable by app/app-container from 'apps/APP'/'app_containers/CONTAINER'

keep ./apps and ./app-containers directory existing and empty

the ./apps directory is just one default position to place your apps when webmatrix running, but where to place your code is free.

Explanation

So many developers use webpack, they select different versions of webpack(v1, v2, or even more release in the future), different plugins/presets of babel, they meet one same problem:

How I share my common config for two or more revelant projects?

you can copy the common config if you have a small number of projects, or use git-submodule to manage them, but that's too complicated.

cooking-cli

cooking-cli and webmatrix @<0.0.4-alpha choose to find the config for every project, which leads one problem coming:

If I make sense of one field in cooking's config, I must know the config for webpack initiazlied by vue-cli, I should be familar for the code-snippets and config format written in vue-cli's template. So why don't me re-initialize one new project by vue-cli ?

generally, if you use vue-cli to generate one project by webpack, you'd be never strange to the code below:

css-pre-precessor-in-vue-project-template

var path = require('path')
var config = require('../config')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
 
exports.assetsPath = function (_path) {
  var assetsSubDirectory = process.env.NODE_ENV === 'production'
    ? config.build.assetsSubDirectory
    : config.dev.assetsSubDirectory
  return path.posix.join(assetsSubDirectory, _path)
}
 
exports.cssLoaders = function (options) {
  options = options || {}
 
  var cssLoader = {
    loader: 'css-loader',
    options: {
      minimize: process.env.NODE_ENV === 'production',
      sourceMap: options.sourceMap
    }
  }
 
  // generate loader string to be used with extract text plugin 
  function generateLoaders (loader, loaderOptions) {
    var loaders = [cssLoader]
    if (loader) {
      loaders.push({
        loader: loader + '-loader',
        options: Object.assign({}, loaderOptions, {
          sourceMap: options.sourceMap
        })
      })
    }
 
    // Extract CSS when that option is specified 
    // (which is the case during production build) 
    if (options.extract) {
      return ExtractTextPlugin.extract({
        use: loaders,
        fallback: 'vue-style-loader'
      })
    } else {
      return ['vue-style-loader'].concat(loaders)
    }
  }
 
  // https://vue-loader.vuejs.org/en/configurations/extract-css.html 
  return {
    css: generateLoaders(),
    postcss: generateLoaders(),
    less: generateLoaders('less'),
    sass: generateLoaders('sass', { indentedSyntax: true }),
    scss: generateLoaders('sass'),
    stylus: generateLoaders('stylus'),
    styl: generateLoaders('stylus')
  }
}
 
// Generate loaders for standalone style files (outside of .vue) 
exports.styleLoaders = function (options) {
  var output = []
  var loaders = exports.cssLoaders(options)
  for (var extension in loaders) {
    var loader = loaders[extension]
    output.push({
      test: new RegExp('\\.' + extension + '$'),
      use: loader
    })
  }
  return output
}
 

that's one loaders-generator to deal with css-pre-processer for webpack config, and it's packed to cooking-cli's plugin cooking-vue2, if you want to konw how cooking deal with style, you must read cooking-vue2's code, and then find the source from vue-cli:template:webpack to make sense of the code above.

cooking is grace but not elegant, that is, if you just use vue, so cooking is enough; but if you want use webpack with angular, react and even more MVVM framework, you would like to have just one 'raw' webpack config initiazlied from teamplte and configure it by your self.

convention over configuration

webmatrix has no any plugins yet, because webpack is complicated, it has so many plugin hooks, if you need to hook it, you should make sense of its hook mechanism. I think it follow the principle convention over configuration: use one webpack instance, share config by container, extend in app.

knowdeldge over configuration

if you don't know how connect-history-api-fallback makes project generated by vue-cli:template:webpack can autoreload when files change, the configuration in vue-cli:template:webpack or cooking-cli is confusing of you.

if you are one skilled user of webpack, you can write your own vue-cli's template then init it by yourself by running vue-cli init YOU_TEMPLATE_REPOSITORY rather than just use webmatrix or cooking-cli. for example, you can write your own css-pre-precessor-in-vue-project-template

compact with any webpack-driven project

in webmatrix's template, the file webpack.conf.*.js exports 'approximately empty' webpack config.

integrate to webmatrix

That means, you can import your any exsiting webpack-driven project in app/webpack/web, and run wmweb dev to process the app/webpack/web/webpack.conf.dev.js.

separate from webmatrix

you can also separate your project from specific version webmatrix and, if project depends on, project's app-containers, you just need to install webmatrix and project's container(if required) as project's dependencies, you can even just copy webmatrix and container to your project's node_modules(not recommended).