webpack的一点介绍

Webpack 把任何一个文件都看成一个模块,模块间可以互相依赖(require or import),webpack 的功能是把相互依赖的文件打包在一起。webpack 本身只能处理原生的 JavaScript 模块,但是 loader 转换器可以将各种类型的资源转换成 JavaScript 模块。这样,任何资源都可以成为 Webpack 可以处理的模块。同时,webpack还有丰富的插件 plugin,可以完成例如js,css的压缩,公共依赖模块的提取和注入,甚至利用模板对 html 进行动态拼接等功能。

同时,webpack 使用commonjs规范(require),支持es6语法(import)的编译,可以方便的抽离vue组件,这成为我们选择它的重要理由。

对webpack工作方式直观的理解(官网小示例)

import: es6 引入依赖的方式,还可以用commonjs 规范的require

var bar  = require('./bar')

module.exports: commonjs规范中对外暴露本模块接口的方式。每个模块内部,都有一个module对象,代表当前模块,module对象包含module.id,module.filename,module.exports等信息

entry: 编译的入口js文件,即需要处理的js文件(所有的其他模块包括image,css,vue组件,html模板等都是通过js依赖引入进来的)

output: 编译的出口js文件,即经过打包其他资源、合并、压缩等处理之后生成的js文件

本示例中因为 app.js 依赖 bar.js ,所以打包之后的 bundle.js 可以理解为app.js和bar.js合并后的js

命令行工具中运行:wepack 即编译成功


实际项目中的webpack解析

本项目已支持功能

 1 对less编译
2 对js es6语法支持
3 编译.vue组件,并自动内联组件样式
4 图片打包,包括对html内图片处理(利用html-loader和es6字符串模板),对小图片生成base64
5 利用htmlWebpackPlugin动态拼接html 的公共部分和内容部分,引入相应css/js资源,并构建到指定目录, 对ejs模板支持
6 对js内依赖的css分离并压缩
7 对js引用的公共模块抽取分离成单独文件
8 区分开发环境和生产环境
9 js 压缩
10 静态文件(css/js/img)hash版本支持
11 清除目标文件目录
12 eslint支持并实现自动修复部分问题
13 vue接口请求axios支持
14 热更新,自动编译并刷新浏览器

 

项目目录结构

  |__ html
|__ dist
|__ income.html
|__ index.html
|__ src
|__ income
|__ income.ejs
|__ income.js
|__ index
|__ index.ejs
|__ index.js
|__ layouts
|__ footer.ejs
|__ header.ejs
|__ layout.ejs
|__ layout.js
|__ side-menu.e
|__ top-nav.ejs
|__ dist
|__ css
|__ img
|__ js
|__ income.js
|__ index.js
|__ manifest.js
|__ vendors.js
|__ src
|__ css
|__ img
|__ js
|__ component
|__ App.vue
|__ income.js
|__ index.js
|__ lib
|__ axios.min.js
|__ layer.js
|__ vue.js
|__ vue.min.js
|__ mock
|__ node_modules
|__ webpack-config
|__ .eslintrc.dev.js
|__ .eslintrc.js
|__ postcss.config.js
|__ resolve.config.js
|__ package.json
|__ .babelrc
|__ .eslintrc.js

一. entry介绍

var entries = getEntry('./src/**/*.js') // 获得入口js文件
entries.vendors = ['vue','axios'] module.exports = {
/* 输入文件 */
entry: entries
}

通常我们的项目中有大量的js入口文件,基本一个功能页面有一个js,这时我们的 entry 文件为一个对象格式

entries 为:

{
income: './src/js/income.js',
index: './src/js/index.js',
vendors: [ 'vue', 'axios' ]
}

key 值为对应模块的别名,webpack会依次处理这些模块。

vendors 为公共模块,这里我们把vue, axios设置为公共模块,供下面进行提取公共模块操作。

之所以可以直接写vue, axios,是因为我们在 alias 里设置了别名:

var path = require('path')

module.exports = {
// 模块别名的配置,为了使用方便,一般来说所有模块都是要配置一下别名的
alias: {
'vue': path.resolve(__dirname, '../src/js/lib/vue.min.js'),
'axios': path.resolve(__dirname, '../src/js/lib/axios.min.js')
}
}

这里的 path.resolve 作用是把相对路径转为绝对路径,假设我项目建在d:/demo 目录下,

_dirname: d:\demo

path.resolve(__dirname, '../src/js/lib/vue.min.js'): d:\demo\src\js\lib\vue.min.js

getEntry() 为获取文件路径的自定义函数:

/***** 获取文件列表:输出正确的js和html路径 *****/
var glob = require('glob') function getEntry(globPath) {
var entries = {}, basename glob.sync(globPath).forEach(function (entry) {
//排出layouts内的公共文件
if(entry.indexOf('layouts') == -1 && entry.indexOf('lib') == -1){
basename = path.basename(entry, path.extname(entry))
entries[basename] = entry
}
})
return entries
}

通常webpack的entry入口文件,是功能性页面的js,对于js库等文件不需要列入入口文件进行处理。所以这里对lib文件夹进行了排除。layouts文件夹为获取html路径时需要排除的文件路径。

二. output介绍

module.exports = {
output: {
/* 输出目录,没有则新建 */
path: path.resolve(__dirname, './dist'),
/* 静态目录,可以直接从这里取文件 */
publicPath: 'http://www.xxx.com/dist/',
/* 文件名 */
filename: 'js/[name].js?v=[chunkhash:8]'
}
}

 publicPath: 如果有这项,则html中的引用的js路径会加上publicPath,即 http://www.xxx.com/dist/js/[name].js?v=[chunkhash:8]

 filename: 这里可以自定义输出后的文件名,加上版本号

  [name] :输入模块的别名

  [chunkhash] : 模块的hash值,":8"代表保留8位hash值

  [hash] : 整个编译环境的hash值

hash和chunkhash具体区别请看这里

三. module介绍

loaders: webpack利用各种loader来把不同格式的文件封装成模块加载到js内,比如css-loader, vue-loader

特别注意:webpack v1 和webpack v2 的区别

 module: {
- loaders: [
+ rules: [
{
test: /\.css$/,
- loaders: [
- "style-loader",
- "css-loader?modules=true"
+ use: [
+ {
+ loader: "style-loader"
+ },
+ {
+ loader: "css-loader",
+ options: {
+ modules: true
+ }
+ }
]
},
{
test: /\.jsx$/,
loader: "babel-loader", // Do not use "use" here
options: {
// ...
}
}
]
}

eslint-loader

module: {
rules: [
{
test: /\.js$/,
enforce: 'pre',
loader: 'eslint-loader',
include: path.resolve(__dirname, './src/js/**/*.js'),
exclude: ['./src/js/lib','./src/js/component'],
options: {
fix: true
}
}
]
}

目的是 对js进行代码风格和语法的校验

enforce: 注意这是webpack v2的变动,v1是 preLoaders。设置为pre表示对js的校验在编译之前进行,我们只负责自己写的js 语法和规范没有问题即可,编译后的代码什么样都不管。

通常我们只对自己写的js进行校验,类库和包里的js无需校验。include即声明我们对哪些文件进行校验,相反,exclude是排除校验哪些文件。

fix:true 即在编译时自动修复代码风格和语法问题

babel-loader

{
test: /\.js$/,
loader: 'babel-loader',
exclude: ['node_modules','./src/js/lib','./src/js/component']
}

es6语法目前很多浏览器不支持,我们需要将其转化为大部分浏览器支持的es5语法,这就需要babel-loader

css-loader style-loader post-loader less-loader

{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
},
{
test: /\.less$/,
use: ExtractTextPlugin.extract(['css-loader','postcss-loader','less-loader'])
}

对于有多个loader时,webpack v2也废弃了v1的 " !" 连接,改为数组形式,且不能省略 " -loader " 以免造成名称混乱意思模糊,执行顺序为从右到左

postcss-loader为集合处理css各种问题的平台,其上面有各种插件来处理css,我们这里只用到了autoprefixer插件,后面插件部分会详解

style-loader:可以将css以style内联方式嵌入到html页面

ExtractTextPlugin:提取css, 后面插件部分会进行详解

file-loader url-loader 处理图片

{
test: /\.(png|jpg|gif)$/,
loader: 'url-loader?limit=5120&name=img/[name].[ext]?v=[hash:8]'
}

webpack中处理图片用file-loader,但url-loader有个好处,它可以把小图片转化成base64格式,其他的大图片再用file-loader处理,这里的limit即为临界值,这里定义小于5k图片转成base64格式,大于5k的用file-loader处理。

name: 可以重新定义处理后的图片并加上版本值。

四. 插件plugin

module: {},
plugins: [
new ExtractTextPlugin('css/[name].css?v=[contenthash:6]'),
new webpack.LoaderOptionsPlugin({
options: {
eslint: require( './webpack-config/.eslintrc.js'),
postcss: require( './webpack-config/postcss.config.js')
},
})
]

插件可以补充loader的功能,对其进行丰富完善,webpack声明插件的方式可以像上面的写法也可以如下方式:

module.exports.plugins.push(new htmlWebpackPlugin())

亦或

module.exports.plugins = module.exports.plugins.concat([
//压缩css代码
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css/g,
cssProcessor: require('cssnano'),
cssProcessorOptions: { discardComments: {removeAll: true } },
canPrint: true
}),
//压缩JS代码
new webpack.optimize.UglifyJsPlugin({
output: {
comments: false, // 去掉注释内容
}
})
])

通常后两种写法用于动态的使用插件。

extract-text-webpack-plugin 插件

默认情况下,js依赖引入css,编译后,css被加在js中,如果我们想把css提取出一个单独的文件,可以使用这个插件,并可以对提取出的css进行自定义命名和加版本hash值

income.js中依赖income.less

如果不使用extractTextPlugin,编译后的目录结构为

查看income.js,发现css被引入在js之中,模块id为16

再看下webpack sourcemap下的income.less,css-loader已经将此文件编译成对外暴露的模块形式,模块id为16

使用extractTextPlugin插件后

income.js依赖的income.less被单独提出,income.js中引入的模块16发现提示 removed by extract-text-webpack-plugin,再看下此时的income.less

提示 removed by extract-text-webpack-plugin , 说明此插件已经顺利的将js中的css提取成单文件形式

同时发现html中已插入income.css

这个是style-loader起的作用

LoaderOptionsPlugin插件

加载插件的配置项,比如eslint的语法配置,postcss的插件配置

optimize-css-assets-webpack-plugin 插件

压缩css文件,对从js中提取出的css文件亦有效

注意:此插件是在css被提取出来加了hash值后进行处理,如果css文件提出来后被命名为  css/[name].css?v=[contenthash:8] 形式,插件的使用如下

new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css/g, //注意不要写成 /\.css$/g, 否则匹配不到css文件会导致压缩不成功
cssProcessor: require('cssnano'),
cssProcessorOptions: { discardComments: {removeAll: true } },
canPrint: true
})

html-webpack-plugin 插件

用于根据模板组合html各个部分,并插入对应引用的js,对前后端分离贡献颇多,功能强大会有专门的篇章来介绍

browser-sync-webpack-plugin 插件

热更新,自动刷新浏览器

var BrowserSyncPlugin = require('browser-sync-webpack-plugin')

module.exports = {
plugins: [
new BrowserSyncPlugin({
host: 'localhost',
port: 3000,
server: { baseDir: ['./'] }
})
]
}

baseDir: localhost:3000 指定的目录

结合webpack的watch,可以做到实时编译并刷新浏览器

只需要  webpack --watch  即可

CommonsChunkPlugin 插件

提取js的公共模块,此插件为webpack自带的插件

// 提取公共模块
new webpack.optimize.CommonsChunkPlugin({
names: ['vendors', 'manifest'], // 公共模块的名称
//filename: 'js/[name]-[chunkhash:6].js', // 公共模块的名称
chunks: 'vendors', // chunks是需要提取的模块
minChunks: Infinity //公共模块最小被引用的次数
})

通常我们的js可能会引入一些公共js文件,包括一些类库,如果都打包在一个js中,这个js会变得非常庞大,而且一旦我们功能页面的js有变化,会导致打包后的js版本号进行更新然后重新加载,这个代价有些大,所以我们会考虑把一些公共的js文件提取出一个单独的文件,这样在第一次访问的时候会加载,之后就可以缓存下来,减少服务器请求的压力并提高加载速度。

names: 定义公共js模块的文件名,即vendors.js,manifest是为了存储webpack编译逻辑的一些信息,也会生成一个manifest.js并引入html。如果不生成manifest文件,这些webpack的编译逻辑信息就会存储在vendors中,当incomejs等页面的功能js变化时,也会导致这个公共js的hash值变化,这样又会导致重新加载100多k的vendor.js,这就失去了我们提取公共模块的意义。

而如果多生成一个manifest.js文件,会发现,当incomejs等页面页面功能js变化时,只有manifest.js的hash值有更新,vendors.js的hash值不变,虽然这样会导致重新请求manifest.js但它的体积不过几kb,代价远小于vendorjs,所以我们可以用这种方式来优化我们公共js模块的加载方式。

官网如下解释,可供参考:

To extract the webpack bootstrap logic into a separate file, use the CommonsChunkPlugin on a name which is not defined as entry. Commonly the name manifest is used. See the code splitting libraries guide for details.
new webpack.optimize.CommonsChunkPlugin({
name: "manifest",
minChunks: Infinity
})

filename: 我们可以重命名公共模块的文件名格式,此举会覆盖output中的文件名命名方式,不定义这个属性默认用output中的filename方式

chunks:需要提取的模块,在entry中我们有如下定义  entries.vendors = ['vue','axios']  所以定义   chunks: 'vendors'  就是我们会提取vuejs axiosjs到公共js中

minChunks: 公共模块最小被引用的次数, 可以写成2,3...。Infinity: with more entries, this ensures that no other module goes into the vendor chunk,推荐用infinity

CleanWebpackPlugin插件

清除目标文件

new CleanWebpackPlugin(['dist'])

源码:https://github.com/saysmy/vue2-webpack2-demo

如有错误请指正

html模板拼接详解请见:前后端分离之vue2.0+webpack2 实战项目 -- html模板拼接

转载请注明出处 https://i.cnblogs.com/EditPosts.aspx?postid=6635504

前后端分离之vue2.0+webpack2 实战项目 -- webpack介绍的更多相关文章

  1. 前后端分离之vue2.0+webpack2 实战项目 -- html模板拼接

    对于前后端分离,如何把一个页面的公共部分比如head, header, footer, content等组合成一个完整的html 是一个值得考虑的地方. 对于php,我们可以利用include加载其他 ...

  2. 手把手教你使用 Spring Boot 3 开发上线一个前后端分离的生产级系统(一) - 介绍

    项目简介 novel 是一套基于时下最新 Java 技术栈 Spring Boot 3 + Vue 3 开发的前后端分离的学习型小说项目,配备详细的项目教程手把手教你从零开始开发上线一个生产级别的 J ...

  3. 鲜衣怒马散尽千金,Vue3.0+Tornado6前后端分离集成Web3.0之Metamask钱包区块链虚拟货币三方支付功能

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_219 不得不承认,大多数人并不拥有或者曾经拥有加密货币.是的,Web3.0.加密货币.区块链,对于大多数的互联网用户来说,其实是一 ...

  4. 区块相隔虽一线,俱在支付同冶熔,Vue3.0+Tornado6前后端分离集成Web3.0之Metamask区块链虚拟三方支付功能

    最近几年区块链技术的使用外延持续扩展,去中心化的节点认证机制可以大幅度改进传统的支付结算模式的经营效率,降低交易者的成本并提高收益.但不能否认的是,区块链技术也存在着极大的风险,所谓身怀利器,杀心自起 ...

  5. SpringBoot电商项目实战 — 前后端分离后的优雅部署及Nginx部署实现

    在如今的SpringBoot微服务项目中,前后端分离已成为业界标准使用方式,通过使用nginx等代理方式有效的进行解耦,并且前后端分离会为以后的大型分布式架构.弹性计算架构.微服务架构.多端化服务(多 ...

  6. FastAPI + Vue 前后端分离 接口自动化测试工具 apiAutoTestWeb

    apiAutoTestWeb使用说明 apiAutoTestWeb是为apiAutoTest的可视化版本,其采用前后端分离(FastAPI + Vue2)方式实现 具体使用: Python3 + Fa ...

  7. EF+jQueryUI前后端分离设计

    开源项目练习EF+jQueryUI前后端分离设计   最近大家流行把项目开源,我也来玩玩.只是开源公司项目不好,小弟只好从公司项目经验上另外弄出一套练习开源给大家. 这个项目可以做简单的团队任务系统( ...

  8. SSM框架中的前后端分离

    认识前后端分离 在传统的web应用开发中,大多数的程序员会将浏览器作为前后端的分界线.将浏览器中为用户进行页面展示的部分称之为前端,而将运行在服务器,为前端提供业务逻辑和数据准备的所有代码统称为后端. ...

  9. 《论vue在前后端分离项目中的实践之年终总结》

    我是2014年的时候开始了解知道的vue,当时vue还不太成熟,想用但是又怕自己hold不住,况且那时候vue还没有成熟的(路由.验证.ui组件)插件,社区也是不温不火的,再说也没有合适的机遇让我去项 ...

随机推荐

  1. vue2.0全局组件之pdf

    目的:像elementUI那样注册全局组件 预览pdf文件 技术支持:使用火狐的pdf.js http://mozilla.github.io/pdf.js/ 准备:新建一个CPdf.vue文件,把火 ...

  2. Struts2之访问路径

    上一篇已经和大家分享了关于Struts2命名空间和Action的三种创建方式,本篇我们接着命名空间的内容,来一起探讨一下关于Struts2的访问路径问题,何为访问路径,就是指当我们在浏览器输入地址,点 ...

  3. Spring Cache扩展:注解失效时间+主动刷新缓存

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  4. MySQL C#教程

    这是关于MySQL数据库的C#教程,包含了对MySQL数据库基本操作: 数据库访问组件MySql Connect/NET MySql Connect/NET是MySQL官方提供给C#的接口,封装的非常 ...

  5. apicloud下拉刷新

    //下拉 apiready = function () { var param = {}; toDoRequest(); param.loadingImgae = 'widget://image/re ...

  6. java基础:模拟ATM取款机

    package com.atm; import java.util.Scanner; /** * ATM类实现 * * @author 向往的生活 */ public class ATM { publ ...

  7. KoaHub平台基于Node.js开发的Koa router路由插件代码信息详情

    koa-router Router middleware for koa. Provides RESTful resource routing. koa-router       Router mid ...

  8. Java 反射的理解

    反射反射,程序员的快乐,今天你快乐了吗?如果你不快乐,没关系,接下来让你快乐起来! 一.什么是反射? 通过百度百科我们可以知道,Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性 ...

  9. Linux系统常用命令总结

    1. 最关键的命令 manecho 2. 目录文件操作命令 ls: 查看目录下的文件信息或文件信息dir:pwd: 打印当前路径cd:改变路径mkdir:创建路径rmdir:删除路径cp:拷贝文件或目 ...

  10. 如果服务器不能把编码格式改成UTF8怎么办?(20161113)

    //数组内容的编码格式:utf8 /* 如果服务器不能把编码格式改成UTF8 则在方法里的执行sql语句之前输入下面三段代码就可以使得返回的数组的编码格式为UTF8 $conn->query(' ...