模块化
模块化分为AMD、CMD、CommonJS、ES6四类
一、CommonJS
Node、webpack使用的CommonJS规范, require加载是同步的
// 导入
const moduleA = require('./moduleA');
moduleA.someFun(1,2); // 需要等moduleA加载后在执行,这里是同步
// 导出
module.exports = moduleA.someFunc
二、AMD 异步加载模块
可异步加载依赖模块,可并行加载多个依赖,可以运行浏览器和node环境下,缺点是需要加载AMD的库才能使用,常用的require.js
// 定义模块
define('moduleA', [依赖文件], function(jquery){
var someFun = (x, y) => { return x + y}
return {
someFun,
}
})
// 导入和使用
require(['moduleA'], function(moduleA){
module.someFun(1,2);
})
三、ES6
JS的标准化模块加载,会逐渐的取代commonJS和AMD
// 导入
import React from 'react'
import ReactDOM, { render } from 'react-dom';
// 导出
export function hello(){ ... }
export default {
...
}
export { fn1, fn2 }
四、CMD 同步加载模块
代表seajs
// 定义模块
define(function(require,exports,module){
var $ = require('jquery'); // 用来加载模块
exports.sayHello = function(){ // 导出的接口
...
}
});
构建工具的什么用
1、代码转换 - 将ES6转ES5, 将SCSS转成css
2、文件优化 - 压缩JS、CSS、HTML代码,压缩合并图片
3、代码分割 - 提取多个页面的公共代码,提取首屏不需要执行代码,其它的异步加载
4、模块合并 - 将多个模块合并成一个文件
5、自动刷新 - 监听本地代码变化,并自动构建和刷新浏览器
6、代码校验 - 校验代码是否符合规范
7、自动发布 - 自动构建出线上发布代码并传输给发布系统
webpack安装和命令
$ npm i -D webpack webpack-cli // 安装稳定版本,4版本以上需要装webpack-cli, -D是--save-dev的缩写
npm i -D webpack@3.10.0 // 安装指定版本
$ touch webpack.config.js // 创建配置文件
一、配置npm运行命令
"scripts": {
"start": "webpack --config webpack.config.js"
}
$ npm start // 执行
二、webpack命令
1、webpack // 最基本的启动webpack命令
2、webpack --config XXX.js // 如果默认的配置文件不叫webpack.config.js,就需要在这指定配置文件的名称
script: {
"build": "webpack --config production.config.js",
"dev": "webpack --config development.config.js"
}
3、webpack -w // watch方法,时实预览进行打包 相当于 --watch
4、webpack -p // 对打包后的文件进行压缩
5、webpack -d // 提供SourceMaps,方便调试
6、webpack --colors // 输出结果带彩色,比如: 会用红色显示耗时较长的步骤
7、webpack --profile // 输出性能数据,可以看到每一步的耗时
8、webpack --display-modules // 默认情况下 node_modules 下的模块会被隐藏,加上这个参数可以显示这些被隐藏的模块
9、webpack --progress --colors // 展示一些进度条,同时增加颜色
10、webpack --display-error-details // 打印出错在哪个文件和行
Entry
entry是配置模块的入口,执行构建开始时递归解析所有的入口依赖,配置值: string | object | array
// 单入口
module.exports = {
entry: './src/main.js'
}
// 多入口
module.exports = {
entry: {
main: ["./main.js", "./list.js"]
}
}
// 多入口,app(应用主入口),vendors(公共库)入口
module.exports = {
entry: {
main: './src/main.js',
list: './src/list.js',
vendors: './src/jquery.js' // 加载第三方模块
}
}
Output
配置 output 选项可以控制 webpack 如何向硬盘写入编译文件
output的配置属性:
1、path: 输出的目录,绝对路径
2、filename: 用于输出文件的文件名
变量: 1) id chunk 的唯一标识从0开始 2)name chunk 的名称 3)hash 输出hash值 4)chunkhash 内容的hash值
filename: 'bundle.js'
filename: '[name].js' // 用于多入口
filename: '[chunkhash].js' // 一个随机数,入口为entry chunk
filename: '[name].js[hash]' // 带hash值 [hash:8] 代表8位的hash,默认20位
3、publicPath: 复杂项目里会有一些构建出的资源需要异步加载,加载这些异步资源需要对应的URL
output: {
filename: '[name]_[chunkhash:8].js',
publicPath: 'https://cdn.example.com/assets/' // 发布到线上的HTML <script src="https://cdn.example.com/assets/main.12345678.js"</script>
}
Loader
它的基本工作流是将一个文件以字符串的形式读入,对其进行语法分析及转换, 预处理 CoffeeScript、 TypeScript、ESNext (Babel)、Sass、Less、Stylus
1、rules: 配置模块的读取和解析,将所有引用资源(.css、.html、.scss、.jpg)作为模块处理
2、条件匹配: 通过test、include、exclude三个配置项来选中loader规则文件
test: 匹配哪些文件
include: 指定一个目录下的所有文件,可以加快webpack的搜索速度
exclude: 排除某个目录,不在这个目录搜索文件
3、应用规则: 对选中的文件通过usr配置来应用loader
4、重置顺序: 默认从右向左执行, 通过enforce选项将其中一个loader的顺序放到最前或最后
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: "babel-loader",
},
include: [path.resolve(__dirname, 'src)], // 只在src目录下搜索js文件
}
{
test: /\.css$/,
use: ["style-loader", "css-loader?minimize", "sass-loader"], // minimize 压缩css
exclude: [/node_modules/] // 除了node_modules目录不搜索
}
]
}
插件: npm install --save-dev css-loader
resolve
webpack启动后会从入口找出所有的依赖模块,resolve配置如何寻找模块对应的文件
1、alias 让模块引入变得简单
import $ from '/js/lib/jquery.min.js'; 开发中需要引入jquery就需要写这类路径
通过alias来解决
resolve: {
alias: {
jquery: path.resolve(__dirname, "/js/lib/jquery.min.js"),
},
extensions: ['', '.js', '.vue', '.scss', '.css'] //设置require或import的时候可以不需要带后缀
}
引用
import $ from 'jquery'; // jquery就会被替换成依赖的路径
plugins
plugins扩展webpack功能
一、webpack自带插件,可以直接使用
pulgins: [
new webpack.optimize.UglifyJsPlugin(),
new webpack.optimize.CommonsChunkPlugin({ // webpack自带插件在webpack.optimize内
name: 'vendor', // 上面入口定义的节点组
filename: 'jquery.vendor.js?[hash]' // 最后生成的文件名
})
]
二、非自身插件,需要先调用插件
例: main.js
require('./main.css')
const show = require('./show.js)
show(1,2)
webpack.config.js
// 将引用的css文件提取出来
const ExtractTextPlugin = require('extract-text-webpack-plugin');
pulgins: [
new ExtractTextPlugin({
filename: '[name].[contenthash:8].css', // main.11ad8d2c.css
allChunks: true,
})
]
webpack插件列表: https://www.webpackjs.com/plugins/
devServer
webpack-dev-server - 创建一个本地服务,并能设置代理服务,并且能够实时重新加载
一、安装webpack-dev-server
$ npm i --save-dev webpack-dev-server
二、创建文件
// 创建项目目录
$ mkdir webpack_base_demo && cd webpack_base_demo
// 创建配置文件
$ touch README.md .gitignore .babelrc webpack.config.js
// 创建package.json
$ npm init
// 配置.babelrc文件
{
"presets": ["react", "env"],
"env": {
"development": {
<!-- "plugins": [["react-transform", {
"transforms": [{
"transform": "react-transform-hmr",
"imports": ["react"],
"locals": ["module"]
}]
}]] -->
}
}
}
三、安装需要的loader插件
// 如果使用react框架来做项目,先下载包
$ npm i --save react react-dom
// babel的插件,在react热更新
$ npm i --save babel-plugin-react-transform react-transform-hmr
// 使用Babel-loader来解析es6和react
$ npm i --save babel-core babel-loader babel-preset-env babel-preset-react
// vue-load - 解析和转换.vue文件,vue-template-compiler - 将vue-load提取出的HTML模板编译成可执行的JS代码,vue项目可直接安装vue-cli
$ npm vue-load vue-template-compiler
// jsx转换
$ npm i --save jsx-loader
// css模块化,可以在组件中引用指定模块的css文件, import './main.css'
$ npm i --save style-loader css-loader
// 可以将js和css中的导入的图片替换成正确的地址,同时将文件输出到对应的位置
$ npm i --save file-loader
// 将文件的图片经过base64编码后注入js或css中
$ npm i --save url-loader
// 加载SVG
$ npm i --save svg-loader
// CSS预处理器 autoprefixer 自动加载前缀
$ npm i --save less-loader sass-loader
五、package.json配置
"scripts": {
"dev": "webpack-dev-server --hot --inline --progress",
"start": "webpack --progress --profile --colors --config webpack.config.js",
},
$ npm run start // 启动开发环境
六、创建生成和开发配置文件
webpack.config.js 开发环境所用配置文件
webpack.pub.config.js 生产环境所用配置文件
七、注意
1、启动两个侦听一个是webpack,一个是devServer,单独启devServer热更新不执行编译,暂没找到解决方法
$ npm run build
$ npm run dev
devServer的执行命令
webpack-dev-server - 在 localhost:8080 建立一个 Web 服务器
webpack-dev-server –devtool eval - 为你的代码创建源地址。当有任何报错的时候可以让你更加精确地定位到文件和行号
webpack-dev-server –progress - 显示合并代码进度
webpack-dev-server –colors - 命令行中显示颜色
webpack-dev-server –content-base build // webpack-dev-server服务会默认以当前目录伺服文件,如果设置了content-base的话,服务的根路径则为build目录
webpack-dev-server –inline 可以自动加上dev-server的管理代码,实现热更新
webpack-dev-server –hot 开启代码热替换,可以加上HotModuleReplacementPlugin
webpack-dev-server –port 3000 设置服务端口
webpack与gulp
gulp 是 task runner,Webpack 是 module bundler
webpack对多入口支持的不太好
gulp没有模块化的支持,需要与webpack结合
Source Map
启动时需要加 --devtool source-map 参数重启DevServer后刷新页面,在chrome开发者工具就可以调试源码
常用的处理g
一、css处理
基本问题包括:
预编译语言转换
样式文件挂载方式选择
代码优化(合并及压缩)
去除或保留指定格式的注释
资源定位路径的转换
响应式布局单位转换【可选】
模块化【可选】
处理浏览器兼容【可选】
1、style-loader - 将处理结束的CSS代码存储在js中,运行时嵌入<style>后挂载至html页面上
2、css-loader - 加载器,使webpack可以识别css模块
3、postcss-loader - 加载器,下一篇将详细描述
4、sass-loader - 加载器,使webpack可以识别scss/sass文件,默认使用node-sass进行编译
5、mini-css-extract-plugin - 提取单独的css文件插件,4.0版本启用的插件,替代原extract-text-webpack-plugin插件,将处理后的CSS代码提取为独立的CSS文件
6、optimize-css-assets-webpack-plugin - 插件,实现CSS代码压缩
7、autoprefixer - 自动化添加跨浏览器兼容前缀
二、Assets 资源(图片、json、xml)
* 体积压缩
* 雪碧图合并及引用修正
* 资源的引用路径自动替换
1、file-loader - 处理资源文件打包
2、url-loader - 优化项目中对于资源的引用路径,并设定大小限制
3、html-loader - html中的静态资源替换
module: {
rules: [
{
test:/\.(jpg|png|svg|gif)/,
use:[{
loader:'file-loader',
options:{
outputPath:'imgs/'
}
}]
},
{
test:/\.(jpg|png|svg|gif)/,
use:[{
loader:'url-loader',
options:{
limit: 8129, // 限制图片转base64引用大小
fallback: 'file-loader', // 大小limit的交给file-loader处理
ouputpath: 'imgs/' // 指定输出路径
}
}]
}
]
}
三、处理JS和splitChunk
Js文件打包需求
* 代码编译(TS或ES6代码的编译)
* 脚本合并
* 公共模块识别
* 代码分割
* 代码压缩混淆
1、Babel转换ES6+
webpack.config.js:
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader'
}
]
}
]
},
.bablerc:
{
"presets":[
[
"env",
{
"targets":{
"browsers":"last 2 versions"
}
}
]
],
"plugins": [
"babel-plugin-transform-runtime"
]
}
2、脚本合并
3、脚本分割
为什么要分割,如果遇到比如使用Echarts第三方库或公用文件,这个时候我们不希望把它与业务一起合并到一个文件中,会使这个文件变得非常打,不利于加载
4、代码混淆压缩
UglifyJs
5、splitChunks
用于提取公用文件或第三方组件,4.0废弃了CommonsChunkPlugin插件,使用optimization.splitChunks和optimization.runtimeChunk来代替
vendor 加载公用文件或第三方组件
entry: {
index: path.resolve(basePath, 'js/index.js'),
list: path.resolve(basePath, 'js/list.js'),
vendors: path.resolve(basePath, 'js/common.js'),
},
// 使用optimization,与entry同级,不需要放到plugins内
optimization: {
splitChunks: {
cacheGroups: {
commons: {
name: "vendors",
chunks: "initial",
minChunks: 2
}
}
}
},
plugins: [
new HtmlWebpackPlugin({
title: '首页',
template: path.resolve(basePath, 'index.html'),
filename: path.resolve(buildPath, 'index.html'),
chunks:['index', 'vendors'], // 这里加vendors
inject:'body',
})
]
<!-- module.exports = {
optimization: {
splitChunks: {
chunks: 'async', // 默认只作用于异步模块,为`all`时对所有模块生效,`initial`对同步模块有效
minSize: 30000, // 合并前模块文件的体积
minChunks: 1, // 最少被引用次数
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~', // 自动命名连接符
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
minChunks:1, // 敲黑板
priority: -10 // 优先级更高
},
default: {
test: /[\\/]src[\\/]js[\\/]/
minChunks: 2, // 一般为非第三方公共模块
priority: -20,
reuseExistingChunk: true
}
},
runtimeChunk:{
name:'manifest'
}
}
} -->
解决问题
1、devServer启动时不编译,分别侦听
2、js文件引用动态生成到html文档内
3、第三方插件或公用组件splitChunk
| https://doc.webpack-china.org/concepts/ webpack中文网 v3.10.0
| https://www.jianshu.com/p/42e11515c10f
| http://webpack.wuhaolin.cn/ // book
| https://webpack.js.org/plugins/ // 自带插件
| https://zhuanlan.zhihu.com/p/32148338
| https://blog.csdn.net/keliyxyz/article/details/51571386
| http://react-china.org/t/webpack-output-filename-output-chunkfilename/2256/2 // output.filename 和output.chunkFilename
| http://www.alloyteam.com/2016/02/code-split-by-routes/ 按需加载
|
| 插件
| http://www.cnblogs.com/haogj/p/5160821.html // html-webpack-plugin html多页面构建
|
| 热更新
| https://github.com/gaearon/react-hot-loader // react
| https://github.com/vuejs/vue-loader // vue
国内查看评论需要代理~