webpack + vue最佳实践
webpack
常用命令
1
2
3
4
5
6
7
8
9
10
11
|
$ webpack --display-error-details // 方便出错时能查阅更详尽的信息 $ webpack --config XXX.js // 使用另一份配置文件(比如webpack.config2.js)来打包 $ webpack -- watch // 监听变动并自动打包 $ webpack -p // 压缩混淆脚本,这个非常非常重要! $ webpack -d // 生成map映射文件,告知哪些模块被最终打包到哪里了 $ webpack --progress // 显示进度 |
loaders 用于转换应用程序的资源文件,他们是运行在nodejs下的函数 使用参数来获取一个资源的来源并且返回一个新的来源(资源的位置)
1
2
3
4
|
npm install style-loader --save-dev npm install css-loader --save-dev npm install less -save-dev npm install less -loader --save-dev |
样式独立
1
|
npm install extract-text-webpack-plugin --save-dev |
config
1
2
3
4
5
6
7
8
|
var ExtractTextPlugin = require( "extract-text-webpack-plugin" ); plugins: [ new ExtractTextPlugin( "[name].css" ) ] loaders: [ { test: /\.css$/, loader: ExtractTextPlugin.extract( "css" ) }, { test: /\.less$/, loader: ExtractTextPlugin.extract( "css!less" ) } ] |
配置外部模块
有时我们想引入一个库,比如vue,如果用webpack打包的话,生成的bundle会比较大。但是通过如下的配置可以在页面中引入vue,但是在js文件里还是用require的方式声明。
1
2
3
4
5
|
externals: { // require("jquery") 是引用自外部模块的 // 对应全局变量 jQuery vue: 'window.Vue' } |
index.js
1
|
let Vue = require( "vue" ); |
我们看下vue的这个模块在bundle里是怎么表现的。
1
2
3
4
5
6
|
/*!*****************************!*\ !*** external "window.Vue" ***! \*****************************/ /***/ function (module, exports) { module.exports = window.Vue; /***/ }, |
ES6
webpack + babel可以我们书写ES6代码规范的js了。但是需要加入一些babel转换包
1
|
npm install babel-loader babel-core babel-preset-es2015 --save-dev |
config
1
2
3
4
5
6
|
module: { //加载器配置 loaders: [ { test: /\.js$/, loader: "babel" ,query: {presets: [ 'es2015' ]} } ] }, |
babel
.babelrc
: 该文件用来设置转码规则和插件
1
2
3
4
|
{ "presets" : [ "es2015" , "stage-0" ], "plugins" : [ "transform-runtime" ] } |
1
2
3
4
5
|
babel-preset-es2015 : 2015转码规则 babel-preset-stage-0/1/2/3 : ES7不同阶段语法提案的转码规则(共有4个阶段) babel-core : API转换核心文件 babel-plugin-transform-runtime : 语法转换 babel-polyfill : api polyfill |
Vue
使用vue + webpack来整合项目。这里需要使用vue-loader,由于版本问题,vue version1.x请使用^8.0.0的版本来转换。
这里有一份package.json 的 devDependencies,亲测ok
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
{ "name" : "webpack-demo" , "version" : "1.0.0" , "description" : "" , "main" : "webpack.config.js" , "scripts" : { "dev" : "webpack --watch -d" , "publish" : "webpack -d -p --progress" }, "author" : "" , "license" : "ISC" , "devDependencies" : { "babel-core" : "^6.1.2" , "babel-loader" : "^6.1.0" , "babel-plugin-transform-runtime" : "^6.1.2" , "babel-preset-es2015" : "^6.1.2" , "babel-runtime" : "^5.8.0" , "css-loader" : "^0.23.0" , "extract-text-webpack-plugin" : "^1.0.1" , "less" : "^2.7.1" , "less-loader" : "^2.2.3" , "vue-hot-reload-api" : "^1.2.0" , "vue-html-loader" : "^1.0.0" , "vue-loader" : "^8.0.0" , "vue-style-loader" : "^1.0.0" , "webpack" : "^1.12.2" } } |
webpack.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
var webpack = require( 'webpack' ); var vue = require( 'vue-loader' ) var commonsPlugin = new webpack.optimize.CommonsChunkPlugin( 'common.js' ); var ExtractTextPlugin = require( "extract-text-webpack-plugin" ); module.exports = { //插件项 plugins: [ new ExtractTextPlugin( "[name].css" ) ], //页面入口文件配置 entry: { index : './src/index.js' }, //入口文件输出配置 output: { path: './dist/' , filename: '[name].js' }, module: { //加载器配置 loaders: [ { test: /\.css$/, loader: ExtractTextPlugin.extract( "css" ) }, { test: /\.less$/, loader: ExtractTextPlugin.extract( "css!less" ) }, { test: /\.js$/, loader: "babel" ,query: {presets: [ 'es2015' ]},exclude: /node_modules/ }, { test: /\.vue$/, loader: 'vue' } ] }, vue : { loaders: { css: ExtractTextPlugin.extract( "css" ), less: ExtractTextPlugin.extract( "css!less" ) }, autoprefixer: { browsers: [ "ios_saf >= 7" , "android >= 4" ] } }, externals: { vue: "window.Vue" } }; |
目录结构
1
2
3
4
5
6
7
|
src |____index.css |____index.js |____vue-mods |____index.js |____index. less |____index.vue |
src/index.js
1
2
3
4
5
6
7
|
import "./index.css" ; import Vue from "vue" ; import App from "./vue-mods/index.vue" ; addEventListener( 'DOMContentLoaded' , function () { new Vue(App).$mount( "app" ); }); // moduleA.say(); |
src/vue-mods/index.vue
1
2
3
4
5
6
7
|
< style lang="less" src="./index.less"></ style > < template > < div class="wrap"> {{msg}} </ div > </ template > < script src="./index.js"></ script > |
src/vue-mods/index.js
1
2
3
4
5
6
7
|
export default { data () { return { msg: 'Hello from Component B!' } } } |
执行 npm run build
可以看到 dist
目录
1
2
3
4
5
|
dist |____index.css |____index.css.map |____index.js |____index.js.map |
之前用webpack + vue 做项目一直不是很懂,这次有空梳理下,so,让我们重新开始,我们的目的是:
- 使用commonJs规范编写面向浏览器端的代码
- 升级到可以使用ES2015书写规范
- 使用vue来组织我们的项目代码
资料
- 一小时包教会 —— webpack 入门指南
- vue-loader
- 入门Webpack,看这篇就够了
webpack
常用命令
1
2
3
4
5
6
7
8
9
10
11
|
$ webpack --display-error-details // 方便出错时能查阅更详尽的信息 $ webpack --config XXX.js // 使用另一份配置文件(比如webpack.config2.js)来打包 $ webpack -- watch // 监听变动并自动打包 $ webpack -p // 压缩混淆脚本,这个非常非常重要! $ webpack -d // 生成map映射文件,告知哪些模块被最终打包到哪里了 $ webpack --progress // 显示进度 |
loaders 用于转换应用程序的资源文件,他们是运行在nodejs下的函数 使用参数来获取一个资源的来源并且返回一个新的来源(资源的位置)
1
2
3
4
|
npm install style-loader --save-dev npm install css-loader --save-dev npm install less -save-dev npm install less -loader --save-dev |
样式独立
1
|
npm install extract-text-webpack-plugin --save-dev |
config
1
2
3
4
5
6
7
8
|
var ExtractTextPlugin = require( "extract-text-webpack-plugin" ); plugins: [ new ExtractTextPlugin( "[name].css" ) ] loaders: [ { test: /\.css$/, loader: ExtractTextPlugin.extract( "css" ) }, { test: /\.less$/, loader: ExtractTextPlugin.extract( "css!less" ) } ] |
配置外部模块
有时我们想引入一个库,比如vue,如果用webpack打包的话,生成的bundle会比较大。但是通过如下的配置可以在页面中引入vue,但是在js文件里还是用require的方式声明。
1
2
3
4
5
|
externals: { // require("jquery") 是引用自外部模块的 // 对应全局变量 jQuery vue: 'window.Vue' } |
index.js
1
|
let Vue = require( "vue" ); |
我们看下vue的这个模块在bundle里是怎么表现的。
1
2
3
4
5
6
|
/*!*****************************!*\ !*** external "window.Vue" ***! \*****************************/ /***/ function (module, exports) { module.exports = window.Vue; /***/ }, |
ES6
webpack + babel可以我们书写ES6代码规范的js了。但是需要加入一些babel转换包
1
|
npm install babel-loader babel-core babel-preset-es2015 --save-dev |
config
1
2
3
4
5
6
|
module: { //加载器配置 loaders: [ { test: /\.js$/, loader: "babel" ,query: {presets: [ 'es2015' ]} } ] }, |
babel
.babelrc
: 该文件用来设置转码规则和插件
1
2
3
4
|
{ "presets" : [ "es2015" , "stage-0" ], "plugins" : [ "transform-runtime" ] } |
1
2
3
4
5
|
babel-preset-es2015 : 2015转码规则 babel-preset-stage-0/1/2/3 : ES7不同阶段语法提案的转码规则(共有4个阶段) babel-core : API转换核心文件 babel-plugin-transform-runtime : 语法转换 babel-polyfill : api polyfill |
Vue
使用vue + webpack来整合项目。这里需要使用vue-loader,由于版本问题,vue version1.x请使用^8.0.0的版本来转换。
这里有一份package.json 的 devDependencies,亲测ok
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
{ "name" : "webpack-demo" , "version" : "1.0.0" , "description" : "" , "main" : "webpack.config.js" , "scripts" : { "dev" : "webpack --watch -d" , "publish" : "webpack -d -p --progress" }, "author" : "" , "license" : "ISC" , "devDependencies" : { "babel-core" : "^6.1.2" , "babel-loader" : "^6.1.0" , "babel-plugin-transform-runtime" : "^6.1.2" , "babel-preset-es2015" : "^6.1.2" , "babel-runtime" : "^5.8.0" , "css-loader" : "^0.23.0" , "extract-text-webpack-plugin" : "^1.0.1" , "less" : "^2.7.1" , "less-loader" : "^2.2.3" , "vue-hot-reload-api" : "^1.2.0" , "vue-html-loader" : "^1.0.0" , "vue-loader" : "^8.0.0" , "vue-style-loader" : "^1.0.0" , "webpack" : "^1.12.2" } } |
webpack.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
var webpack = require( 'webpack' ); var vue = require( 'vue-loader' ) var commonsPlugin = new webpack.optimize.CommonsChunkPlugin( 'common.js' ); var ExtractTextPlugin = require( "extract-text-webpack-plugin" ); module.exports = { //插件项 plugins: [ new ExtractTextPlugin( "[name].css" ) ], //页面入口文件配置 entry: { index : './src/index.js' }, //入口文件输出配置 output: { path: './dist/' , filename: '[name].js' }, module: { //加载器配置 loaders: [ { test: /\.css$/, loader: ExtractTextPlugin.extract( "css" ) }, { test: /\.less$/, loader: ExtractTextPlugin.extract( "css!less" ) }, { test: /\.js$/, loader: "babel" ,query: {presets: [ 'es2015' ]},exclude: /node_modules/ }, { test: /\.vue$/, loader: 'vue' } ] }, vue : { loaders: { css: ExtractTextPlugin.extract( "css" ), less: ExtractTextPlugin.extract( "css!less" ) }, autoprefixer: { browsers: [ "ios_saf >= 7" , "android >= 4" ] } }, externals: { vue: "window.Vue" } }; |
目录结构
1
2
3
4
5
6
7
|
src |____index.css |____index.js |____vue-mods |____index.js |____index. less |____index.vue |
src/index.js
1
2
3
4
5
6
7
|
import "./index.css" ; import Vue from "vue" ; import App from "./vue-mods/index.vue" ; addEventListener( 'DOMContentLoaded' , function () { new Vue(App).$mount( "app" ); }); // moduleA.say(); |
src/vue-mods/index.vue
1
2
3
4
5
6
7
|
< style lang="less" src="./index.less"></ style > < template > < div class="wrap"> {{msg}} </ div > </ template > < script src="./index.js"></ script > |
src/vue-mods/index.js
1
2
3
4
5
6
7
|
export default { data () { return { msg: 'Hello from Component B!' } } } |
执行 npm run build
可以看到 dist
目录
1
2
3
4
5
|
dist |____index.css |____index.css.map |____index.js |____index.js.map |
效果图如下