webpack是一个现代的JavaScript应用的静态模块打包工具。
涉及到两个概念:模块 和 打包css
经过模块化开发完成项目后,还须要处理模块间的各类依赖,而且将其进行整合打包。而webpack其中一个核心就是让咱们可能进行模块化开发,而且会帮助咱们处理模块间的依赖关系。并且不只仅是JavaScript文件,咱们的CSS、图片、json文件等等在webpack中均可以被当作模块来使用。这就是webpack中模块化的概念。html
就是将webpack中的各类资源模块进行打包合并成一个或多个包(Bundle)。而且在打包的过程当中,还能够对资源进行处理,好比压缩图片,将scss
转成css
,将ES6
语法转成ES5
语法,将TypeScript
转成JavaScript
等等操做。前端
但打包的操做彷佛grunt/gulp也能够帮助咱们完成,它们有什么不一样呢?vue
grunt/gulp的核心是Task
咱们能够配置一系列的task
,而且定义task
要处理的事务(例如ES六、ts转化,图片压缩,scss转成css)。以后让grunt/gulp
来依次执行这些task
,并且让整个流程自动化。因此grunt/gulp也被称为前端自动化任务管理工具。node
来看一个gulp的task:下面的task就是将src下面的全部js文件转成ES5的语法。而且最终输出到dist文件夹中。webpack
const gu1p = requireC('gulp'); const babe1 = require('gu1p-babe1'); gulp.task('js',()=> gulp.src('src/*.js') .pipe(babe1({ presets: ['es2015'] })) .pipe(gulp. dest('dist')) );
何时用grunt/gulp呢?
若是你的工程模块依赖很是简单,甚至是没有用到模块化的概念。只须要进行简单的合并、压缩,就使用grunt/gulp便可。可是若是整个项目使用了模块化管理,并且相互依赖很是强,咱们就可使用更增强大的webpack了。
因此,grunt/gulp和webpack有什么不一样呢?web
grunt/gulp
更增强调的是前端流程的自动化,模块化不是它的核心。webpack
更增强调模块化开发管理,而文件压缩合并、预处理等功能,是他附带的功能。安装webpack首先须要安装Node.js,Node.js自带了软件包管理工具npm。express
cnpm install webpack --save-dev //--save-dev是开发时依赖,项目打包后不须要继续使用的。
在终端直接执行webpack命令,使用的全局安装的webpack。当在package.json中定义了scripts时,其中包含了webpack命令,那么使用的是局部webpack。npm
文件和文件夹解析:
dist文件夹:用于存放以后打包的文件
src文件夹:用于存放咱们写的源文件
-----main.js项目的入口 文件。具体内容查看下面详情。
index.html:浏览器打开展现的首页html
package.json:经过npm init生成的,npm包管理的文件(暂时没有用上,后面才会用上)json
js文件的打包
webpack src/main.js dist/bundle.js
使用打包后的文件
打包后会在dist文件下,生成一个bundle.js文件。bundle.js文件,是webpack处理了项目直接文件依赖后生成的一个js文件,咱们只须要将这个js文件在index.html中引入便可
若是每次使用webpack的命令都须要写上入口和出口做为参数,有一种方法能够将这两个参数写到配置中,在运行时,直接读取。
建立一个webpack.config.js文件
const path = require('path') module.exports = { //入口:能够是字符串/数组/对象,这里咱们入口只有一个,因此写一个字符串便可 entry:'./src/main.js' , //出口:一般是一个对象,里面至少包含两个重要属性,path 和filename output:{ path: path. resolve(__dirname, 'dist'), //注意: path一般是一 个绝对路径 filename: 'bundle.js' } }
由于一个项目每每依赖特定的webpack版本,全局的版本可能很这个项目的webpack版本不一致,导出打包出现问题。因此一般一个项目,都有本身局部的webpack。
//安装指定本身须要的版本 cnpm install webpack@3.6.0 --save-dev //启动webpack打包 node_modules/.bin/webpack
咱们能够在package.json的scripts中定义本身的执行脚本。
{ "name": "meetwebpack", "version": "1.0.0", "description":"", "main": 'index.js', "scripts": { "build": "'webpack" }, "author":"", "license":"ISC", "devDependencies": { "webpack": "^3. 6. 0" } }
package.json中的scripts的脚本在执行时,会按照必定的顺序寻找命令对应的位置。
首先,会寻找本地的node_modules/.bin路径中对应的命令。若是没有找到,会去全局的环境变量中寻找。
//执行build指令 cnpm run build
什么是loader?
loader是webpack中一个很是核心的概念。在开发中咱们不只仅有基本的js代码处理,咱们也须要加载css、图片,也包括一些高级的将ES6转成ES5代码,将TypeScript转成ES5代码,将scss、less转成css,将.jsx、.vue文件转成js文件等等。对于webpack自己的能力来讲,对于这些转化是不支持的。此时须要给webpack扩展对应的loader。
loader使用过程:
步骤一:经过npm安装须要使用的loader
步骤二:在webpack.config.js中的modules关键字下进行配置
大部分loader咱们均可以在webpack的官网中找到,而且学习对应的用法。loader 的执行顺序是从下到上,从右到左。
须要用到两个loader:css-loader 和 style-loader。css-loader
负责加载css文件;style-loader
负责将css具体样式嵌入到文档中。
安装
cnpm install --save-dev css-loader style-loader
webpack.config.js中配置
const path = require('path'); module.exports = { mode: 'development', entry: { main: './src/index.js' }, output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, module:{ rules:[ { test:/\.css$/, use:['style-loader','css-loader'], } ] }, }
由于webpack在读取使用的loader的过程当中,是按照从右向左的顺序读取的。因此style-loader
须要放在css-loader
的前面。
须要安装less 和 less-loader。
rules: [{ test: /\.less$/, use: [{ loader: "style-loader" // creates style nodes from JS strings }, { loader: "css-loader" // translates CSS into CommonJS }, { loader: "less-loader" // compiles Less to CSS }] }]
url-loader、file-loader
当加载的图片, 小于limit
时, 会将图片编译成base64
字符串形式.
当加载的图片, 大于limit
时, 须要使用file-loader
模块进行加载.
修改文件名称
当图片大于limit时,使用file-loader
默认会将该图片打包从新命名为32位的hash值放到dist文件夹下。
{ test: /\.(png|jpg|gif|jpeg)$/, use: [ { loader: 'url-loader', options: { // 当加载的图片, 小于limit时, 会将图片编译成base64字符串形式. // 当加载的图片, 大于limit时, 须要使用file-loader模块进行加载. limit: 13000, // [ext]:表示原始文件名的后缀。[name]:表示原始文件名。[hash:8]:为了防止图片名称冲突,依然使用hash,可是咱们只保留8位 name: 'img/[name].[hash:8].[ext]' }, } ] },
咱们发现图片并无显示出来,这是由于图片使用的路径不正确。默认状况下,webpack会将生成的路径直接返回给使用者可是,咱们整个程序是打包在dist文件夹下的,因此这里咱们须要在路径下再添加一个dist/
。
output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js', publicPath: 'dist/' },
若是但愿将ES6的语法转成ES5,那么就须要使用babel。而在webpack中,咱们直接使用babel对应的loader就能够了。
npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
配置webpack.config.js文件
{ test: /\.js$/, // exclude: 排除 // include: 包含 exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['es2015'] } } }
plugin
是插件的意思,一般是用于对某个现有的架构进行扩展。webpack中的插件,就是对webpack现有功能的各类扩展,好比打包优化,文件压缩等等。
loader
主要用于转换某些类型的模块,它是一个转换器。plugin
是插件,它是对webpack自己的扩展,是一个扩展器。
步骤一:经过npm安装须要使用的plugins(某些webpack已经内置的插件不须要安装)
步骤二:在webpack.config.js中的plugins中配置插件。
BannerPlugin
,属于webpack自带的插件。
const path = require('path') const webpack = require('webpack') module.exports = { ... plugins: [ new webpack.BannerPlugin('最终版权归aaa全部'), ], }
在真实发布项目时,须要将index.html文件打包到dist文件夹中,这个时候就可使用 HtmlWebpackPlugin
插件。HtmlWebpackPlugin
插件能够为咱们作这些事情:自动生成一个index.html文件(能够指定模板来生成)将打包的js文件,自动经过script标签插入到body中。
npm install html-webpack-plugin --save-dev
const path = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { ... plugins: [ new HtmlWebpackPlugin({ template: 'index.html'//指定生成Html文件时使用的模板。 }), ], }
另外,咱们须要删除以前在output
中添加的publicPath
属性,不然插入的script标签中的src可能会有问题。
CleanWebpackPlugin 会在打包以前删除指定目录下的内容。
npm install clean-webpack-plugin -D
webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin'); //注意加{} module.exports = { ... plugins:[ new HtmlWebpackPlugin({ template: 'src/index.html' }), new CleanWebpackPlugin() //不能加参数。 ], }
webpack提供了一个可选的本地开发服务器,这个本地服务器基于node.js搭建,内部使用express框架,能够实现咱们想要的让浏览器自动刷新显示咱们修改后的结果。
npm install --save-dev webpack-dev-server@2.9.1
devserver
也是做为webpack中的一个选项,选项自己能够设置以下属性:
`contentBase`:为哪个文件夹提供本地服务,默认是根文件夹,咱们这里要填写./dist `port`:端口号 `inline`:页面实时刷新 `historyApiFallback`:在SPA页面中,依赖HTML5的history模式
devServer: { contentBase: './dist', inline: true }
能够再配置另一个scripts:--open参数表示直接打开浏览器
"scripts": { "build": "webpack", "dev": "webpack-dev-server --open" },
在前面的Vue实例中,咱们定义了el属性,用于和index.html中的#app进行绑定,让Vue实例以后能够管理它其中的内容。
这里,咱们能够将div元素中的{{message}}内容删掉,只保留一个基本的id为div的元素
可是若是我依然但愿在其中显示{{message}}的内容,应该怎么处理呢?
咱们能够再定义一个template属性,代码以下:
new Vue({ el: '#app', template: '<div id="app">{{message}}</div>', data: { message:'coderwhy' } })
el和template模板的关系是什么呢?
el用于指定Vue要管理的DOM,能够帮助解析其中的指令、事件监听等等。
而若是Vue实例中同时指定了template,那么template模板的内容会替换掉挂载的对应el的模板。这样作以后咱们就不须要在之后的开发中再次操做index.html,只须要在template中写入对应的标签便可
稍后会将template
模板中的内容进行抽离。会分红三部分书写:template
、script
、style
,结构变得很是清晰。
main.js
//使用Vue进行开发 import Vue from 'vue' import App from './vue/App.vue' new Vue({ el: '#app', template: '<App/>', components: { App } })
vue-->App.vue
<template> <div> <h2 class="title">{{message}}</h2> <h2>{{name}}</h2> </div> </template> <script> export default { name: "App", data() { return { message: 'Hello Webpack', name: '张三' } }, } </script> <style scoped> .title { color: green; } </style>
安装vue、vue-loader 和 vue-template-compiler 进行处理。
npm install vue-loader vue-template-compiler --save-dev
cnpm install vue --save
module: { rules: [ { test: /\.vue$/, use: ['vue-loader'] } ] }, //解决runtime-only版本的Vue报错 resolve: { // alias: 别名 extensions: ['.js', '.css', '.vue'], alias: { 'vue$': 'vue/dist/vue.esm.js' } }