webpack/babel笔记

babel 基础

link

babel-core

是作为babel的核心存在,负责转义ast,
import {tranform, transformFile, transformFileSync, transformFromAst } from ‘babel-core’

babel-cli

babel-cli是一个通过命令行对js文件进行换码的工具。
babel script.js

babel-node

这是一个支持ES6的js执行环境。

babel-register

底层改写了node的require方法,引入babel-register之后所有require并以.es6, .es, .jsx 和 .js为后缀的模块都会经过babel的转译。

1
2
3
4
5
6
7
8
9
10
11
//test.js
const name = 'shenfq';
module.exports = () => {
const json = {name};
return json;
};
//main.js
require('babel-register');
var test = require('./test.js'); //test.js中的es6语法将被转译成es5

console.log(test.toString()); //通过toString方法,看看控制台输出的函数是否被转译

babel-polyfill

polyfill在代码中的作用主要是用已经存在的语法和api实现一些浏览器还没有实现的api,对浏览器的一些缺陷做一些修补。例如Array新增了includes方法,箭头函数、解构赋值、class、Promise
.babelrc babel run command缩写

官方唯一推荐preset:babel-preset-env。

webpack 大致运行流程

  1. 获取配置参数 webpack.config.js
  2. 实例化Compiler, 通过run方法开启编译 //Compiler类,
  3. 根据入口文件, 创建依赖项, 并递归获取所有模块的依赖模块 //
  4. 通过loader去解析匹配到的模块
  5. 获取模板, 把解析好的数据套进不同的模板 // 切割模块儿模板,
  6. 输出文件到指定路径

如何编写一个Loader

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// stylus-loader

const stylus = require('stylus')
function loader (source) {
let css = ''
stylus.render(source, (err, data) => {
if (!err) {
css = data
} else {
throw new Error(error)
}
})
return css
}
module.exports = loader

// style-loader

function loader (source) {
let script = `
let style = document.createElement('style')
style.innerHTML = ${JSON.stringify(source)}
document.body.appendChild(style)
`
return script
}
module.exports = loader

//使用:

// webpack.config.js
const path = require('path')
const root = path.join(__dirname, './')

const config = {
mode : 'development',
entry : path.join(root, 'src/app.js'),
output : {
path : path.join(root, 'dist'),
filename : 'bundle.js'
},
module : {
rules : [
{
test : /\.styl(us)?$/,
use : [ //root, loaders 路径名称
path.join(root, 'loaders', 'style-loader.js'),
path.join(root, 'loaders', 'stylus-loader.js')
]
}
]
}
}


module.exports = config

// app.js

const name = require('./js/moduleA.js')
require('./style/init.styl')


const oH1 = document.createElement('h1')
oH1.innerHTML = 'Hello ' + name
document.body.appendChild(oH1)

如何写一个webpack插件

1、一个 js 命名函数。
2、在原型链上存在一个 apply 方法。
3、为该插件指定一个 Webpack 的事件钩子函数。
4、使用 Webpack 内部的实例对象(Compiler 或者 Compilation)具有的属性或者方法。
5、当功能完成以后,需要执行 Webpack 的回调函数。

1
2
3
4
5
6
7
8
function myExampleWebpackPlugin( ){  }
myExampleWebpackPlugin.prototype.apply = function(Compiler){
Compiler.plugin(‘compilation’,function(compilation,callback){
console.log(‘this is an example plugin’);
callback( );
})
}
`

Compiler 对象: Compiler 对象代表了 Webpack 完整的可配置的环境。
该对象在 Webpack 启动的时候会被创建,同时该对象也会被传入一些可控的配置,如 Options、Loaders、Plugins。
当插件被实例化的时候,会收到一个 Compiler 对象,通过这个对象可以访问 Webpack 的内部环境。

Compilation 对象: Compilation 对象在每次文件变化的时候都会被创建,因此会重新产生新的打包资源。
该对象表示本次打包的模块、编译的资源、文件改变和监听的依赖文件的状态。

如何手写一个简单的webpack

link

clean-webpack-plugin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const CleanWebpackPlugin = require('clean-webpack-plugin’); 不必每一次都有手动清除dist,自动清除。

purifycss-webpack css优化去重去无效代码
css打包优化去重去无效代码 https://blog.csdn.net/zhoulucky1993/article/details/85228990

const PurifyCSS = require("purifycss-webpack");

new PurifyCSS({
paths: glob.sync([
// 要做CSS Tree Shaking的路径文件
path.join(__dirname, ".html"),
path.join(__dirname, "src/*.js")
])
})

extract-text-webpack-plugin

该插件的主要是为了抽离css样式,防止将样式打包在js中引起页面样式加载错乱的现象。

glob-all , glob

在webpack中的使用。
link

读取某个文件夹下所有的文件。

1
2
3
4
5
6
7
glob("./src/components/**/*.js", function (er, files) {
console.log(files);
return files
});
// [ './src/components/index/index.js',
// './src/components/news/n.js',
// './src/components/news/news.js' ]

webpack3-webpack4升级

从webpack4开始官方移除了commonchunk插件,改用了optimization属性进行更加灵活的配置,这也应该是从V3升级到V4的代码修改过程中最为复杂的一部分,
下面的代码即是optimize.splitChunks 中的一些配置参考

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
module.exports = {
optimization: {
runtimeChunk: {
name: 'manifest'
},
minimizer: true, // [new UglifyJsPlugin({...})]
splitChunks:{
chunks: 'async’, //表示哪些代码需要优化,有三个可选值:initial(初始块)、async(按需加载块)、all(全部块),默认为async
minSize: 30000, //表示在压缩前的最小模块大小,默认为30000
minChunks: 1, //表示被引用次数,默认为1
maxAsyncRequests: 5, //按需加载时候最大的并行请求数,默认为5
maxInitialRequests: 3, //一个入口最大的并行请求数,默认为3
automaticNameDelimiter: ‘~’, //命名连接符
name: false, //拆分出来块的名字,默认由块名和hash值自动生成

cacheGroups: { //缓存组。缓存组的属性除上面所有属性外,还有test, priority, reuseExistingChunk
* test: 用于控制哪些模块被这个缓存组匹配到
* priority: 缓存组打包的先后优先级
* reuseExistingChunk: 如果当前代码块包含的模块已经有了,就不在产生一个新的代码块
vendor: {
name: 'vendor',
chunks: 'initial',
priority: -10,
reuseExistingChunk: false,
test: /node_modules\/(.*)\.js/,
default:true/false //开启禁用default缓存组
},
styles: {
name: 'styles',
test: /\.(scss|css)$/,
chunks: 'all',
minChunks: 1,
reuseExistingChunk: true,
enforce: true
}
}
}
}
}

chunks的取值是有initial, async, all。默认情况下是async,
initial , all 模式会将所有来自node_modules的模块分配到一个叫vendors的缓存组;所有重复引用至少两次的代码,会被分配到default的缓存组。
https://www.codercto.com/a/26564.html 关于配置splitChunk的一些介绍,不是很懂。

babel-polyfill和babel-runtime区别

babel-polyfill会有一定副作用,比如:
引入了新的全局对象:比如Promise、WeakMap等。
修改现有的全局对象:比如修改了Array、String的原型链等。
举个例子,我在项目中定义了跟规范不一致的Array.from()函数,同时引入了一个库(依赖babel-polyfill),
此时,这个库可能覆盖了自定义的Array.from()函数,导致出错。

babel-runtime存在的原因。它将开发者依赖的全局内置对象等,抽取成单独的模块,并通过模块导入的方式引入,避免了对全局作用域的修改(污染)。
因此,如果是开发库、工具,可以考虑使用 babel-runtime。

babel-plugin-transform-runtime和 babel-runtime 区别

link

babel-plugin-transform-runtime

用于构建过程的代码转换,babel-runtime是实际导入项目代码的功能模块。

1
2
3
4
var promise = new Promise;     ->  `npm bin`/babel index.js
=>
import _Promise from "babel-runtime/core-js/promise”; //babel-runtime
var promise = new _Promise();

babelrc 详解

babel 用法及其 .babelrc 的配置详解,想做前端架构,拒绝一知半解
如何写好.babelrc?Babel的presets和plugins配置解析

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
40
41
42
43
44
45
46
es2015(es6集合 )
{
"presets": [ //presets 其实就是一堆plugins的预设起到了方便的作用 如果不采用 presets 完全可以单独引用某个功能
["env",{
“targets”:{
“browsers”:[“last 2 version”,”safari>=7"]
}
}],
[“es2015”],
[“latest”],
[“react"]
],
"plugins": [
"transform-runtime” //babel-runtime是实际导入项目代码的功能模块。转码后额外require core-js的模块如promise class等等
"transform-es2015-classes”,
"transform-regenerator”,
"transform-runtime", {
"helpers": true,
"polyfill”:false, //设置为false可以优化代码
"regenerator": true,
"moduleName": "babel-runtime"
}

]
}

transform-runtime
var sym = Symbol();
var promise = new Promise( );
console.log(arr[Symbol.iterator]( ));

"use strict”;
var _getIterator2 = require("@babel/runtime-corejs2/core-js/get-iterator");
var _getIterator3 = _interopRequireDefault(_getIterator2);
var _promise = require("@babel/runtime-corejs2/core-js/promise");
var _promise2 = _interopRequireDefault(_promise);
var _symbol = require("@babel/runtime-corejs2/core-js/symbol”);
var _symbol2 = _interopRequireDefault(_symbol);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
var sym = (0, _symbol2.default)();
var promise = new _promise2.default();
console.log((0, _getIterator3.default)(arr));

`

webpack处理css文件

css-loader css-loader 中 importLoaders 选项的作用是,用于配置 css-loader 作用于 @import 的资源之前需要经过其他 loader 的个数。@ import 用于 css 源码中引用 其他模块的关键字,如果你的项目中确定不会涉及模块化,可以忽略此配置项。

style-loader 如果需要将编译后的 css文件独立导出,则须将 style-loader 替换为 extract-text­-webpack-plugin,

1
2
3
4
5
6
7
npm install css-loader style-loader --save-dev  
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
]

webpack处理图片文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
npm install url-loader --save-dev // 处理图片文件 
npm install file-loader -D //如果不正确
rules: [
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 8192,
name: path.posix.join('','img/[name].[hash:7].[ext]')
}
// 添加到这并且会按照文件大小, 或者转化为 base64, 或者单独作为文件
//在大小限制可以name属性/[name].[ext],会将我们的文件生成在设定的文件夹下。
},
]

实现Npm run dev

1
2
3
4
5
npm install webpack-dev-server -D //
"scripts": {
“build": "webpack”, //生成dict,build压缩后的文件
"dev": "webpack-dev-server --config ./webpack.config.js”//不压缩直接在线跑
}