.
├── README.md
├── build
│ ├── devtool.js // 服务配置
│ ├── entry.js // 获取全部的入口路径
│ ├── output.js // 输出
│ ├── plugins.js // 配置插件
├── package.json
├── webpack.config.dev.js // 开发环境配置
├── webpack.config.js // 生产环境配置
└── src
├── assets // 静态目录
│ ├── less // 基本样式和基础依赖
│ ├── mixin.less
│ ├── reset.less
│ ├── variable.less
│ ├── images // 图片
│ ├── home
│ ├── home.png
│ ├── index.png
│ ├── about.png
│ ├── fonts // 字体
│ ├── a.woff
├── components // 组件
│ ├── button.vue
├── entry // 入口js
│ ├── home
│ ├── home.js
│ ├── index.js
│ ├── about.js
├── page // 页面模块
│ ├── home
│ ├── home.vue
│ ├── index.vue
│ ├── about.vue复制代码
.
├── dist
├── css
├── html
├── js
├── images
├── fonts
├── vendor复制代码
在命令面板输入以下命令可建立新的目录:mkdir vue2-webpack3css
2.1 直接在cli里输入命令 cd vue2-webpack3 进入项目
2.2 而后输入命令 npm init,而后依次输入相关的信息后输入yes保存相关的项目信息
2.3 这时候项目里多了一个package.json文件,这个文件里保存了咱们项目相关的一些信息,具体状况能够移步 package.json说明文档html
你们都知道,webpack的配置文件主要由:entry,output,module,plugins,devtool等几部分构成,为了方便管理(若是全在一个文件内,随着项目的庞大会致使配置页面的内容过多),我单独为除了module之外的几个属性创建了文件 前端
由于咱们是多页面应用,因此咱们的入口文件确定是很是多的,为了方便获取全部的入口文件,咱们能够利用Node的fs文件系统来获取entry目录下的全部入口文件的路径,代码以下:vue
const fs = require('fs');
const path = require('path');
const directory = path.resolve(__dirname, '../src/entry') ;
const entryList = {};
(getEntry = (dir) => {
const entryArr = fs.readdirSync(dir);
let pathName,
filePath;
entryArr.forEach(function(filename) {
filePath = dir + '/' + filename;
if(fs.statSync(filePath).isDirectory()) {
getEntry(filePath);
} else {
pathName = filePath.split('entry/')[1].replace('.js', '');
entryList[pathName] = filePath;
}
})
})(directory)
module.exports = entryList复制代码
简单的解析下这段代码,主要是利用到了fs.readdirSync和fs.statSync两个方法。fs.readdirSync方法可以根据你提供路径,获取该路径下的全部文件路径,好比上面代码中我传递的dir(须要注意fs.readdirSync的参数必须是一个绝对路径,相对路径没法获取),fs.readdirSync会返回entry下全部文件的路径,而后咱们拿到这些路径之后,再根据fs.statSync来判断这个路径对应的是一个文件仍是一个目录,若是是目录,那就再调用一次,直到拿到文件的路径。node
const path = require('path');
module.exports = {
path: path.resolve(__dirname, '../dist'),
// publicPath: 'http://img.xxx.com',
filename: 'js/[name].js?ver=[hash:6]'
}复制代码
配置很简单,path把全部的文件都输出到dist目录里,filename把全部的js文件都输出到dist/js目录下,同时[name]对应的是入口文件中的pathName,若是有须要,也能够对publicPath进行配置,好比静态单独打包到了一个服务器上,那么咱们就须要对静态的路径作统一的处理了。webpack
rules: [
{
test: /\.less$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract(['css-loader', 'less-loader'])
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
less: ExtractTextPlugin.extract({
use: ['css-loader', 'less-loader'],
fallback: 'vue-style-loader'
})
}
}
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.(jpg|jpeg|png|gif)$/,
loaders: 'url-loader',
options: {
limit: 10000
}
},
{
test: /\.(woff|woff2|svg|eot|ttf)$/,
use: 'file-loader'
}
]复制代码
loader的配置很简单,可是须要注意几个问题。
1)我指望的是可以把vue组件中的样式和less的样式单独抽离到css文件中,因此须要利用extract-text-webpack-plugin这个插件,后面会讲到这个插件的使用
2)我指望可以利用插件自动补齐css样式的前缀,因此引入了postcss-loader转换器和autoprefixer规则,关于自动补齐的配置,我直接新建个postcss.config.js,而后作了以下简单的配置:git
module.exports = {
plugins: {
'autoprefixer': {}
}
}复制代码
如此配置之后,项目编译less的时候会默认读取该配置文件的内容并根据内容进行后续的处理。
3)我还指望可以在开发的时候用上es6语法,因此咱们须要依赖babel来实现转译,webpack中也有babel-loader来作这个事情,咱们须要执行下面的命令来安装相关的插件:es6
npm i babel-loader babel-core babel-preset-env babel-plugin-transform-runtime --save-dev
npm i babel-runtime --save复制代码
安装完后,新建一个.babelrc文件用来配置babel,代码以下:github
{
presets: [
[
'env',
{
'targets': {
'browsers': ['last 2 versions', 'ie >= 8']
}
}
]
],
plugins: ['transform-runtime']
}复制代码
简单说下配置
presets的做用主要是告诉babel用哪一个语法版原本进行转译(其实presets就是一堆插件的集合),好比说常见的是babel-preset-es2015,配置以下:web
{
presets: ['es2015']
}复制代码
按照这个配置babel会将全部的属于es2015正式版本的语法转译为es5的语法,那么一些es2016,es2017之类的语法是没法被转译的,并且如今一些现代浏览器对于es2015+的支持也愈来愈好,有时候也并非全部的语法都须要转译,因此babel推出了新的配置,也就是.babelrc的配置,‘env’这个配置能够指定咱们指望转译最低兼容的浏览器,好比这里配置的是浏览器最新的两个版本和ie8以上的版本,并且对于es2015+的语法也是一样支持的。
plugins的做用很简单就是引入插件,这里引入了个transform-runtime的插件,它的做用在文章结束时会提到。
1)由于是多页面项目,因此咱们的html页面都须要前端自行建立,为了不进行这些无用的重复操做,我引入了html-webpack-plugin插件,代码以下:
const entry = require('./entry');
let configPlugins = [];
// 根据入口js数组生成页面
Object.keys(entry).forEach((item) => {
config = {
filename: '../dist/html/' + item + '.html',
template: path.resolve(__dirname, '../src/index.html'),
chunks: [item]
}
configPlugins.push(new HtmlWebpackPlugin(config));
})复制代码
首先要将入口路径数组引入进来,由于html-webpack-plugin插件的用法就是实例化一次就会生成一个页面,因此咱们对entry的key进行了循环,在每一次的循环中,根据key的信息生成config,而后实例化HtmlWebpackPlugin插件,如此就能够根据entry生成咱们想要的html目录和页面
2)上面讲到了extract-text-webpack-plugin插件提取css并生成css文件,配置代码以下:
new ExtractTextPlugin({
filename: 'css/[name].css'
})复制代码
该配置会根据入口的目录结构和文件名称在css中生成对应的结构和css文件,[name]一样取决于pathName
3)生成了css文件后,我还指望可以对通用的css和js进行提取,因此引入了CommonsChunkPlugin,这个插件提供了对chunk中公共的部分进行提取并生成文件的能力,配置以下:
new webpack.optimize.CommonsChunkPlugin({
name: 'reset',
filename: 'vendor/common.js',
minChunks: 3
})复制代码
第一个name属性决定了提取出来的公共css文件的名称,这个reset.css文件会生成到css目录下
第二个filename属性决定了公共js的目录和名称,该common.js会生成到vendor目录下
第三个minChunks决定了当有多少个入口文件都含有该模块会对该模块进行抽离,我设置为3,意味着只有当至少3个入口js中都拥有某个相同的部分,才会对该部分进行提取。
ps:在提取的时候要注意个问题,CommonsChunkPlugin只提供了提取公用部分并生成文件的能力,而并无提供往html页面中自动生成公共文件引入的能力,全部咱们须要在模板文件中默认引入公共文件。
4)热更新功能对于任何一个开发人员来讲确定是必不可少的,webpack.HotModuleReplacementPlugin插件提供了这个能力,不过在使用这个插件以前,咱们要先安装个webpack-dev-server插件,两个插件结合才能够实现这个热更新的功能。
5)clean-webpack-plugin插件也是必不可少的,它可以在每次编译完成以前先帮助咱们删除指定的目录以及目录下全部的文件,这种作法可以帮助咱们确保每次生成的代码都是最新的。配置代码以下:
new CleanWebpackPlugin(['dist'], {
root: path.resolve(__dirname, '../')
})复制代码
resolve: {
extensions: ['.js', '.vue', '.less'],
alias: {
less$: path.resolve(__dirname, 'src/assets/less'),
components$: path.resolve(__dirname, 'src/components')
}
}复制代码
extensions的做用主要是方便咱们在引入别的文件时能够省略后缀
alias的做用是设置一些路径的别名,那么在引入别的文件的时候,就能够利用该别名来替代冗长的路径
ps:这里提一下path.resolve,为何要使用它,是为了保证全部模块引入时地址的统一,毕竟项目的结构是有各类层级的,若是不进行统一,那么不一样结构的模块引入时的路径也会不同。
var path = require('path');
module.exports = {
contentBase: path.resolve(__dirname, '../dist'),
host: 'we.cli', // 别忘了配置host哦
port: 8001, // 端口8001
inline: true, // 能够监控js变化
hot: true, // 热启动
compress: true,
watchContentBase: false
};复制代码
1)压缩css
这个比较简单,只须要在每一个css-loader后面增长一个minimize参数就好了,以下:
{
test: /\.less$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract(['css-loader?minimize', 'less-loader'])
}复制代码
2) 压缩js
对js的压缩须要依赖webpack.optimize.UglifyJsPlugin插件,咱们将plugins.js插件复制一个副本,重命名为plugins.prod.js,而后引入webpack.optimize.UglifyJsPlugin插件,配置以下:
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})复制代码
3) 压缩html页面
咱们还能够对html页面进行压缩,以达到进一步减小页面体积的效果,而HtmlWebpackPlugin插件自己已经具有这个能力,新增个minify配置便可,配置以下:
Object.keys(entry).forEach((item) => {
config = {
filename: '../dist/html/' + item + '.html',
template: path.resolve(__dirname, '../src/index.html'),
chunks: [item],
minify: {
// 移除HTML中的注释
removeComments: true,
// 删除空白符与换行符
collapseWhitespace: true
}
}
configPlugins.push(new HtmlWebpackPlugin(config));
})复制代码
好了,经历了这些步骤之后,项目就构建完了。有兴趣的能够到github上clone代码下来运行看看,地址: github.com/FedWithMori…
从babel的官网你能够看到babel-preset-es2015其实就是包含了如下这些插件的集合:
transform-es2015-arrow-functions
transform-es2015-block-scoped-functions
transform-es2015-block-scoping
transform-es2015-classes
transform-es2015-computed-properties
transform-es2015-constants
transform-es2015-destructuring
transform-es2015-for-of
transform-es2015-function-name
transform-es2015-literals
transform-es2015-modules-commonjs
transform-es2015-object-super
transform-es2015-parameters
transform-es2015-shorthand-properties
transform-es2015-spread
transform-es2015-sticky-regex
transform-es2015-template-literals
transform-es2015-typeof-symbol
transform-es2015-unicode-regex
transform-regenerator
经过这个咱们能够知道,不必定要引入babel-preset-es2015,你也能够针对某个特别的新特性进行单独的转译配置
答案能够参考下 segmentfault.com/q/101000000… 的高分回答
大概的做用就是在编译的时候默认会使用babel-runtime的工具函数,从而减小编译后的代码量
webpack文档:doc.webpack-china.org/concepts/
webpack loader:doc.webpack-china.org/loaders/
webpack插件:doc.webpack-china.org/plugins/
Babel的presets和plugins配置解析:excaliburhan.com/post/babel-…
vue-loader:vue-loader.vuejs.org/zh-cn/start…
最后悄悄打个小广告,欢迎对前端兴趣的朋友加入QQ群:474471759