-
Notifications
You must be signed in to change notification settings - Fork 213
Vue preset #484
Vue preset #484
Changes from 9 commits
2d446bf
b47adff
884a0af
1b803e3
dacdc59
147a6b7
578753b
7a79aa1
688f53a
863fa59
a7b138d
f01c2c6
2b0e622
7301a1f
4733bb8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
const Config = require('webpack-chain'); | ||
const merge = require('deepmerge'); | ||
const Future = require('fluture'); | ||
const { tail, equals } = require('ramda'); | ||
const mitt = require('mitt'); | ||
const { | ||
defaultTo, is, map, omit, prop | ||
|
@@ -26,14 +27,28 @@ const pathOptions = [ | |
|
||
// getOptions :: Object? -> IO Object | ||
const getOptions = (opts = {}) => { | ||
let fileExtensions = new Set(['js', 'jsx', 'vue', 'ts', 'mjs']); | ||
const options = merge({ | ||
env: { | ||
NODE_ENV: 'development' | ||
}, | ||
debug: false, | ||
quiet: false | ||
quiet: false, | ||
extensions: fileExtensions | ||
}, opts); | ||
|
||
Object.defineProperty(options, 'extensions', { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @eliperelman Let me know if this is the way you wanted it to be done. Once we've agreed on a way, I could update the rest neutrino to use it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As discussed in IRC, this can just be a normal property, and consumers can access the Set directly. We can also expose a method for generating a regex on the fly, but we don't want to limit this property to only creating regexes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another thing, a user should be able to pass this as an array to Neutrino module.exports = {
options: {
extensions: ['vue']
}
};
// ...
new Set([...this.options.extensions, ...extensions]) When merging we should also probably normalize the values to ensure they don't contain dots. |
||
enumerable: true, | ||
get() { | ||
return [...fileExtensions]; | ||
}, | ||
set(extensions) { | ||
const newExtensions = extensions.map(ext => equals(ext[0], '.') ? tail(ext) : ext); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be simplified to: const newExtensions = extensions.map(ext => ext.replace('.', '')); |
||
|
||
fileExtensions = [...new Set(newExtensions)]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like the original value of fileExtensions = new Set(newExtensions); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Combining this with my previous comment, this can be one-lined into: fileExtensions = new Set(extensions.map(ext => ext.replace('.', ''))); |
||
} | ||
}); | ||
|
||
Object | ||
.keys(options.env) | ||
.forEach(env => process.env[env] = options.env[env]); | ||
|
@@ -87,6 +102,10 @@ class Api { | |
this.config = new Config(); | ||
} | ||
|
||
regexFromExtensions(extensions = this.options.extensions) { | ||
return new RegExp(`.(${extensions.join('|')})$`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❤️ |
||
} | ||
|
||
emit(...args) { | ||
return this.emitter.emit(...args); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/test/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,256 @@ | ||
# Neutrino Vue Preset | ||
|
||
[![NPM version][npm-image]][npm-url] | ||
[![NPM downloads][npm-downloads]][npm-url] | ||
[![Join the Neutrino community on Spectrum][spectrum-image]][spectrum-url] | ||
|
||
## Features | ||
|
||
- Zero upfront configuration necessary to start developing and building a Vue web app | ||
- Modern Babel compilation. | ||
- Extends from [@neutrinojs/web](https://neutrino.js.org/packages/web) | ||
- Modern Babel compilation supporting ES modules, last 2 major browser versions, async functions, and dynamic imports | ||
- Webpack loaders for importing HTML, CSS, images, icons, fonts, and web workers | ||
- Webpack Dev Server during development | ||
- Automatic creation of HTML pages, no templating necessary | ||
- Hot Module Replacement support | ||
- Tree-shaking to create smaller bundles | ||
- Production-optimized bundles with Babili minification, easy chunking, and scope-hoisted modules for faster execution | ||
- Easily extensible to customize your project as needed | ||
|
||
## Requirements | ||
|
||
- Node.js v6.10+ | ||
- Yarn or npm client | ||
- Neutrino v7 | ||
|
||
## Installation | ||
|
||
`@neutrinojs/vue` can be installed via the Yarn or npm clients. Inside your project, make sure | ||
`neutrino` and `@neutrinojs/vue` are development dependencies. You will also need Vue for actual | ||
Vue development. | ||
|
||
#### Yarn | ||
|
||
```bash | ||
❯ yarn add --dev neutrino @neutrinojs/vue | ||
❯ yarn add vue | ||
``` | ||
|
||
#### npm | ||
|
||
```bash | ||
❯ npm install --save-dev neutrino @neutrinojs/vue | ||
❯ npm install --save vue | ||
|
||
|
||
## Project Layout | ||
|
||
`@neutrinojs/vue` follows the standard [project layout](https://neutrino.js.org/project-layout) specified by Neutrino. This | ||
means that by default all project source code should live in a directory named `src` in the root of the | ||
project. This includes JavaScript files, CSS stylesheets, images, and any other assets that would be available | ||
to import your compiled project. | ||
|
||
## Quickstart | ||
|
||
After installing Neutrino and the Vue preset, add a new directory named `src` in the root of the project, with | ||
two files `index.js` and `App.vue` in it. | ||
|
||
```bash | ||
❯ mkdir src && touch src/index.js && touch src/App.vue | ||
``` | ||
|
||
This Vue preset exposes an element in the page with an ID of `root` to which you can mount your application. Edit | ||
your `src/index.js` file with the following: | ||
|
||
```js | ||
import Vue from 'vue'; | ||
import App from './App.vue'; | ||
|
||
new Vue({ | ||
el: '#root', | ||
render: (h) => h(App), | ||
}); | ||
``` | ||
|
||
Next, edit your `src/App.vue` with the following: | ||
|
||
```html | ||
<script> | ||
export default { | ||
name: 'App', | ||
data() { | ||
return {}; | ||
} | ||
}; | ||
</script> | ||
|
||
<template> | ||
<div> | ||
<h1>Hello world!</h1> | ||
</div> | ||
</template> | ||
``` | ||
|
||
Now edit your project's package.json to add commands for starting and building the application: | ||
|
||
```json | ||
{ | ||
"scripts": { | ||
"start": "neutrino start --use @neutrinojs/vue", | ||
"build": "neutrino build --use @neutrinojs/vue" | ||
} | ||
} | ||
``` | ||
|
||
If you are using `.neutrinorc.js`, add this preset to your use array instead of `--use` flags: | ||
|
||
```js | ||
module.exports = { | ||
use: ['@neutrinojs/vue'] | ||
}; | ||
``` | ||
|
||
#### Yarn | ||
|
||
```bash | ||
❯ yarn start | ||
✔ Development server running on: http://localhost:5000 | ||
✔ Build completed | ||
``` | ||
|
||
#### npm | ||
|
||
```bash | ||
❯ npm start | ||
✔ Development server running on: http://localhost:5000 | ||
✔ Build completed | ||
``` | ||
|
||
Start the app, then open a browser to the address in the console: | ||
|
||
## Building | ||
|
||
`@neutrinojs/vue` builds static assets to the `build` directory by default when running `neutrino build`. Using | ||
the quick start example above as a reference: | ||
|
||
```bash | ||
❯ yarn build | ||
|
||
✔ Building project completed | ||
Hash: b26ff013b5a2d5f7b824 | ||
Version: webpack 3.5.6 | ||
Time: 9773ms | ||
Asset Size Chunks Chunk Names | ||
index.dfbad882ab3d86bfd747.js 181 kB index [emitted] index | ||
runtime.3d9f9d2453f192a2b10f.js 1.51 kB runtime [emitted] runtime | ||
index.html 846 bytes [emitted] | ||
✨ Done in 14.62s. | ||
``` | ||
|
||
You can either serve or deploy the contents of this `build` directory as a static site. | ||
|
||
## Static assets | ||
|
||
If you wish to copy files to the build directory that are not imported from application code, you can place | ||
them in a directory within `src` called `static`. All files in this directory will be copied from `src/static` | ||
to `build/static`. To change this behavior, specify your own patterns with | ||
[@neutrinojs/copy](https://neutrino.js.org/packages/copy). | ||
|
||
## Paths | ||
|
||
The `@neutrinojs/web` preset loads assets relative to the path of your application by setting Webpack's | ||
[`output.publicPath`](https://webpack.js.org/configuration/output/#output-publicpath) to `./`. If you wish to load | ||
assets instead from a CDN, or if you wish to change to an absolute path for your application, customize your build to | ||
override `output.publicPath`. See the [Customizing](#Customizing) section below. | ||
|
||
|
||
## Preset options | ||
|
||
You can provide custom options and have them merged with this preset's default options to easily affect how this | ||
preset builds. You can modify Vue preset settings from `.neutrinorc.js` by overriding with an options object. Use | ||
an array pair instead of a string to supply these options in `.neutrinorc.js`. | ||
|
||
The following shows how you can pass an options object to the Vue preset and override its options. See the | ||
[Web documentation](https://neutrino.js.org/packages/web#preset-options) for specific options you can override with this object. | ||
|
||
```js | ||
module.exports = { | ||
use: [ | ||
['@neutrinojs/vue', { | ||
/* preset options */ | ||
|
||
// Example: disable Hot Module Replacement | ||
hot: false, | ||
|
||
// Example: change the page title | ||
html: { | ||
title: 'Epic Vue App' | ||
}, | ||
|
||
// Target specific browsers with babel-preset-env | ||
targets: { | ||
browsers: [ | ||
'last 1 Chrome versions', | ||
'last 1 Firefox versions' | ||
] | ||
}, | ||
|
||
// Add additional Babel plugins, presets, or env options | ||
babel: { | ||
// Override options for babel-preset-env: | ||
presets: [ | ||
['babel-preset-env', { | ||
modules: false, | ||
useBuiltIns: true, | ||
exclude: ['transform-regenerator', 'transform-async-to-generator'], | ||
}] | ||
] | ||
} | ||
}] | ||
] | ||
}; | ||
``` | ||
|
||
## Customizing | ||
|
||
To override the build configuration, start with the documentation on [customization](https://neutrino.js.org/customization). | ||
`@neutrinojs/vue` does not use any additional named rules, loaders, or plugins that aren't already in use by the | ||
Web preset. See the [Web documentation customization](https://neutrino.js.org/packages/web#customizing) | ||
for preset-specific configuration to override. | ||
|
||
### Advanced configuration | ||
|
||
By following the [customization guide](https://neutrino.js.org/customization) and knowing the rule, loader, and plugin IDs from | ||
`@neutrinojs/web`, you can override and augment the build by providing a function to your `.neutrinorc.js` use | ||
array. You can also make these changes from the Neutrino API in custom middleware. | ||
|
||
#### Vendoring | ||
|
||
By defining an entry point named `vendor` you can split out external dependencies into a chunk separate | ||
from your application code. | ||
|
||
_Example: Put Vue into a separate "vendor" chunk:_ | ||
|
||
```js | ||
module.exports = { | ||
use: [ | ||
'@neutrinojs/vue', | ||
(neutrino) => neutrino.config | ||
.entry('vendor') | ||
.add('vue') | ||
] | ||
}; | ||
``` | ||
|
||
## Contributing | ||
|
||
This preset is part of the [neutrino-dev](https://github.com/mozilla-neutrino/neutrino-dev) repository, a monorepo | ||
containing all resources for developing Neutrino and its core presets and middleware. Follow the | ||
[contributing guide](https://neutrino.js.org/contributing) for details. | ||
|
||
[npm-image]: https://img.shields.io/npm/v/@neutrinojs/vue.svg | ||
[npm-downloads]: https://img.shields.io/npm/dt/@neutrinojs/vue.svg | ||
[npm-url]: https://npmjs.org/package/@neutrinojs/vue | ||
[spectrum-image]: https://withspectrum.github.io/badge/badge.svg | ||
[spectrum-url]: https://spectrum.chat/neutrino |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
const web = require('@neutrinojs/web'); | ||
const path = require('path'); | ||
const merge = require('deepmerge'); | ||
const loaderMerge = require('@neutrinojs/loader-merge'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: move this require to be above the |
||
|
||
const MODULES = path.join(__dirname, 'node_modules'); | ||
|
||
module.exports = (neutrino, options) => { | ||
neutrino.use(web, options); | ||
neutrino.options.extensions = ['vue']; // eslint-disable-line no-param-reassign | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We now have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I include the
If extensions is something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, should we include There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like this: jantimon/html-webpack-plugin#602 Basically, I think the vue-loader is only supposed to accept neutrino.config.module
.rule('vue')
.test(/\.vue$/) // instead of .test(neutrino.regexFromExtensions())
.use('vue')
.loader(require.resolve('vue-loader'))
.options(options); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I...don't know. Give it a shot and see if the tests continue to pass, but I'm not sure what effect it may have. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's what I figured, sounds good! Btw, instead of hardcoding There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 😍 |
||
|
||
neutrino.config.module | ||
.rule('vue') | ||
.test(neutrino.regexFromExtensions()) | ||
.use('vue') | ||
.loader(require.resolve('vue-loader')) | ||
.options(options); | ||
|
||
neutrino.config.when(neutrino.config.module.rules.has('lint'), () => { | ||
neutrino.use(loaderMerge('lint', 'eslint'), { | ||
plugins: ['vue'], | ||
envs: ['node'], | ||
parserOptions: { | ||
ecmaFeatures: { | ||
jsx: true | ||
} | ||
}, | ||
rules: { | ||
'vue/jsx-uses-vars': 2 | ||
} | ||
}); | ||
}); | ||
|
||
if (neutrino.config.plugins.has('stylelint')) { | ||
neutrino.config.plugin('stylelint') | ||
.tap(([options, ...args]) => [ | ||
merge(options, { | ||
files: ['**/*.vue'], | ||
config: { | ||
processors: [require.resolve('stylelint-processor-html')], | ||
rules: { | ||
// allows empty <style> in vue components | ||
'no-empty-source': null | ||
} | ||
} | ||
}), | ||
...args | ||
]); | ||
} | ||
|
||
neutrino.config | ||
.resolve | ||
.modules.add(MODULES).end() | ||
.extensions.add('.vue').end() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should make this automatic from the neutrino.config.resolve.extensions.merge(neutrino.options.extensions.map(ext => `.${ext}`); Something like that. |
||
.end() | ||
.resolveLoader.modules.add(MODULES); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
{ | ||
"name": "@neutrinojs/vue", | ||
"version": "7.3.2", | ||
"description": "Neutrino preset adding Vue.js support.", | ||
"main": "src/index.js", | ||
"author": "Capi Etheriel <barraponto@gmail.com> (https://barraponto.blog.br)", | ||
"license": "MPL-2.0", | ||
"peerDependencies": { | ||
"neutrino": "^7.0.0" | ||
}, | ||
"devDependencies": { | ||
"neutrino": "^7.2.1" | ||
}, | ||
"keywords": [ | ||
"neutrino", | ||
"neutrino-preset", | ||
"vue", | ||
"web", | ||
"hot module replacement" | ||
], | ||
"dependencies": { | ||
"@neutrinojs/web": "^7.3.2", | ||
"@neutrinojs/loader-merge": "^7.3.2", | ||
"babel-preset-vue": "^1.2.1", | ||
"deepmerge": "^1.5.2", | ||
"eslint-plugin-vue": "^2.1.0", | ||
"stylelint-processor-html": "^1.0.0", | ||
"vue-loader": "^13.5.0", | ||
"vue-template-compiler": "^2.5.6" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this a peerDependency of something? I don't see this used anywhere. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, it's a peerDependency of |
||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's rename this to
moduleExtensions
so it's clear we are only dealing with module code instead of things like images and stylesheets.