Skip to content

Commit

Permalink
GH-9, allow async registering of components
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-jimenezgarcia-ow committed May 17, 2019
1 parent 0ad415d commit f397907
Show file tree
Hide file tree
Showing 22 changed files with 538 additions and 179 deletions.
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,23 @@ Vue plugin with conventions for automatically wiring components, pages and route

- Docs will be available at https://kaizendorks.github.io/vue-autowire/.

Use it by cloning the repo and building with `npm run build`.
Use it by cloning the repo and building with `npm run build`.

```
import Vue from 'vue'
import App from './App.vue'
import VueAutowire from './autowire';
Vue.config.productionTip = false
Vue.use(VueAutowire, {
// All .js and .vue files except the ones ending with .async.vue
context: require.context('./', true, /\/(?:[^.]+|(?!\.async\.vue$))(\.js|\.vue)$/),
// All the .async.vue files as async components on their own vue file
asyncContext: require.context('./', true, /async\.vue$/, 'lazy')
})
new Vue({
render: h => h(App),
}).$mount('#app')
```
117 changes: 89 additions & 28 deletions dist/vue-autowire.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,83 +8,144 @@
var _defaults = {
routes: {
enabled: true,
pattern: /\.router.js/
pattern: /\.router.js$/
},
components: {
enabled: false,
enabled: true,
pattern: /\/components\/.*\.vue$/
}
};

/**
* Register ruoter files by loading them with webpack.require and wire up Router instance to Vue
* Load router files
* @param {Vue} Vue VueJS instance
* @param {require} requireInstance
* @param {Object} options
*/
function registerRoutes (Vue, requireInstance, options) {
var routeFiles = requireInstance
function registerRoutes (Vue, options) {
var routeFiles = options.requireContext
.keys()
.filter(function (file) { return file.match(options.routes.pattern); });

return routeFiles.map(function (routeFile) {
var routerConfig = requireInstance(routeFile);
var routerConfig = options.requireContext(routeFile);
return routerConfig.default ? routerConfig.default : routerConfig;
});
}

/**
* Register ruoter files by loading them with webpack.require and wire up Router instance to Vue
* Register components files using Vue.component and requiring the file from the context
* @param {Vue} Vue VueJS instance
* @param {require} requireInstance
* @param {Object} options
*/
function registerComponents (Vue, requireInstance, options) {
var componentsFiles = requireInstance
function registerComponents (Vue, options) {
var componentsFiles = options.requireContext
.keys()
.filter(function (file) { return file.match(options.components.pattern); });

var getFileName = function (name) { return /\/([^\/]*)\.vue$/.exec(name)[1]; };

return componentsFiles.map(function (file) {
var name = getFileName(file);
var vueFile = requireInstance(file);
var component = vueFile.hasOwnProperty('default') ? vueFile.default : vueFile;
return Vue.component(name, component);
var component = options.requireContext(file);
// Unwrap "default" from ES6 module
if (component.hasOwnProperty('default')) { component = component.default; }
Vue.component(name, component);

// Return the registered component
return Vue.component(name);
});
}

/**
@param {Object} options User defined options to be parsed
@returns {Object} * @param {Object} options
* Register components files using Vue.component as async components by setting up a factory function using the requireAsyncContext
* Each of these components will be on its own chunk
* @param {Vue} Vue VueJS instance
* @param {Object} options
*/
function parseOptions (options) {
options = options || {};
function registerAsyncComponents (Vue, options) {
var componentsFiles = options.requireAsyncContext
.keys()
.filter(function (file) { return file.match(options.components.pattern); });

var getFileName = function (name) { return /\/([^\/]*)\.async\.vue$/.exec(name)[1]; };

return componentsFiles.map(function (file) {
var name = getFileName(file);
// Register as async component https://vuejs.org/v2/guide/components-dynamic-async.html#Async-Components
Vue.component(
name,
function () { return options.requireAsyncContext(file); }
);

// Return the registered component
return Vue.component(name);
});
}

/**
* Merges user provided options with the library defaults
* @param {Object} userOptions User defined options to be parsed
* @returns {Object}
*/
function parseOptions (userOptions) {
userOptions = userOptions || {};

return {
routes: Object.assign({}, _defaults.routes, options.routes),
components: Object.assign({}, _defaults.components, options.components)
// context and asyncContext are user provided using the require.context API
// which allows a 4th argument to specify the mode in which to load files
// By default this is 'sync', but can be made async as in require.context('./', true, /async\.vue$/, 'lazy')
// See https://github.com/webpack/docs/wiki/context#context-module-api
requireContext: userOptions.context,
requireAsyncContext: userOptions.asyncContext && userOptions.asyncContext.id.includes("lazy") ?
userOptions.asyncContext :
null,

// Async mode is enabled/disabled depending on the last argument provided to require.context
// For example, enable async with: require.context('./', true, /(\.js|\.vue)$/, 'lazy')
// async: requireContext.id.includes("lazy"),

// Merge user-specific options for each of the different asset types
routes: Object.assign({}, _defaults.routes, userOptions.routes),
components: Object.assign({}, _defaults.components, userOptions.components)
};
}

function register (options, context, Vue) {
options = parseOptions(options);
/**
* Register each of the different type of assets if they are enabled by the options
* @param {Object} Vue The Vue API
* @param {Object} userOptions User defined options to be parsed
* @param {require} requireContext webpack require.context instance. https://github.com/webpack/docs/wiki/context#context-module-api
* @returns {Object} The Autowire object with all the assets that were wired
*/
function register (Vue, userOptions) {
var options = parseOptions(userOptions);

// Returned autowiring object with registered elements
var aw = {
routes: [],
components: []
};
if (options.routes.enabled) {
aw.routes = registerRoutes(Vue, context, options);
if (options.routes.enabled && options.requireContext) {
aw.routes.push(registerRoutes(Vue, options));
}
if (options.components.enabled && options.requireContext) {
aw.components.push(registerComponents(Vue, options));
}
if (options.components.enabled) {
aw.components = registerComponents(Vue, context, options);
if (options.components.enabled && options.requireAsyncContext) {
aw.components.push(registerAsyncComponents(Vue, options));
}

return aw;
}

function install (Vue, options) {
Vue.autowire = register(options, options.context, Vue);
/**
* Vue plugin definition. See https://vuejs.org/v2/guide/plugins.html#Writing-a-Plugin
* @param {Object} Vue The Vue API
* @param {Object} userOptions User defined options
* @returns {Object} The Autowire object with all the assets that were wired
*/
function install (Vue, userOptions) {
Vue.autowire = register(Vue, userOptions);
}

module.exports = install;
117 changes: 89 additions & 28 deletions dist/vue-autowire.esm.browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,83 +6,144 @@
const _defaults = {
routes: {
enabled: true,
pattern: /\.router.js/
pattern: /\.router.js$/
},
components: {
enabled: false,
enabled: true,
pattern: /\/components\/.*\.vue$/
}
};

/**
* Register ruoter files by loading them with webpack.require and wire up Router instance to Vue
* Load router files
* @param {Vue} Vue VueJS instance
* @param {require} requireInstance
* @param {Object} options
*/
function registerRoutes (Vue, requireInstance, options) {
const routeFiles = requireInstance
function registerRoutes (Vue, options) {
const routeFiles = options.requireContext
.keys()
.filter(file => file.match(options.routes.pattern));

return routeFiles.map(routeFile => {
const routerConfig = requireInstance(routeFile);
const routerConfig = options.requireContext(routeFile);
return routerConfig.default ? routerConfig.default : routerConfig;
});
}

/**
* Register ruoter files by loading them with webpack.require and wire up Router instance to Vue
* Register components files using Vue.component and requiring the file from the context
* @param {Vue} Vue VueJS instance
* @param {require} requireInstance
* @param {Object} options
*/
function registerComponents (Vue, requireInstance, options) {
const componentsFiles = requireInstance
function registerComponents (Vue, options) {
const componentsFiles = options.requireContext
.keys()
.filter(file => file.match(options.components.pattern));

const getFileName = name => /\/([^\/]*)\.vue$/.exec(name)[1];

return componentsFiles.map(file => {
const name = getFileName(file);
const vueFile = requireInstance(file);
const component = vueFile.hasOwnProperty('default') ? vueFile.default : vueFile;
return Vue.component(name, component);
let component = options.requireContext(file);
// Unwrap "default" from ES6 module
if (component.hasOwnProperty('default')) component = component.default;
Vue.component(name, component);

// Return the registered component
return Vue.component(name);
});
}

/**
@param {Object} options User defined options to be parsed
@returns {Object} * @param {Object} options
* Register components files using Vue.component as async components by setting up a factory function using the requireAsyncContext
* Each of these components will be on its own chunk
* @param {Vue} Vue VueJS instance
* @param {Object} options
*/
function parseOptions (options) {
options = options || {};
function registerAsyncComponents (Vue, options) {
const componentsFiles = options.requireAsyncContext
.keys()
.filter(file => file.match(options.components.pattern));

const getFileName = name => /\/([^\/]*)\.async\.vue$/.exec(name)[1];

return componentsFiles.map(file => {
const name = getFileName(file);
// Register as async component https://vuejs.org/v2/guide/components-dynamic-async.html#Async-Components
Vue.component(
name,
() => options.requireAsyncContext(file)
);

// Return the registered component
return Vue.component(name);
});
}

/**
* Merges user provided options with the library defaults
* @param {Object} userOptions User defined options to be parsed
* @returns {Object}
*/
function parseOptions (userOptions) {
userOptions = userOptions || {};

return {
routes: Object.assign({}, _defaults.routes, options.routes),
components: Object.assign({}, _defaults.components, options.components)
// context and asyncContext are user provided using the require.context API
// which allows a 4th argument to specify the mode in which to load files
// By default this is 'sync', but can be made async as in require.context('./', true, /async\.vue$/, 'lazy')
// See https://github.com/webpack/docs/wiki/context#context-module-api
requireContext: userOptions.context,
requireAsyncContext: userOptions.asyncContext && userOptions.asyncContext.id.includes("lazy") ?
userOptions.asyncContext :
null,

// Async mode is enabled/disabled depending on the last argument provided to require.context
// For example, enable async with: require.context('./', true, /(\.js|\.vue)$/, 'lazy')
// async: requireContext.id.includes("lazy"),

// Merge user-specific options for each of the different asset types
routes: Object.assign({}, _defaults.routes, userOptions.routes),
components: Object.assign({}, _defaults.components, userOptions.components)
};
}

function register (options, context, Vue) {
options = parseOptions(options);
/**
* Register each of the different type of assets if they are enabled by the options
* @param {Object} Vue The Vue API
* @param {Object} userOptions User defined options to be parsed
* @param {require} requireContext webpack require.context instance. https://github.com/webpack/docs/wiki/context#context-module-api
* @returns {Object} The Autowire object with all the assets that were wired
*/
function register (Vue, userOptions) {
const options = parseOptions(userOptions);

// Returned autowiring object with registered elements
const aw = {
routes: [],
components: []
};
if (options.routes.enabled) {
aw.routes = registerRoutes(Vue, context, options);
if (options.routes.enabled && options.requireContext) {
aw.routes.push(registerRoutes(Vue, options));
}
if (options.components.enabled && options.requireContext) {
aw.components.push(registerComponents(Vue, options));
}
if (options.components.enabled) {
aw.components = registerComponents(Vue, context, options);
if (options.components.enabled && options.requireAsyncContext) {
aw.components.push(registerAsyncComponents(Vue, options));
}

return aw;
}

function install (Vue, options) {
Vue.autowire = register(options, options.context, Vue);
/**
* Vue plugin definition. See https://vuejs.org/v2/guide/plugins.html#Writing-a-Plugin
* @param {Object} Vue The Vue API
* @param {Object} userOptions User defined options
* @returns {Object} The Autowire object with all the assets that were wired
*/
function install (Vue, userOptions) {
Vue.autowire = register(Vue, userOptions);
}

export default install;
2 changes: 1 addition & 1 deletion dist/vue-autowire.esm.browser.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f397907

Please sign in to comment.