文章内容输出来源:拉勾教育大前端高薪训练营
模块化演变过程
模块化规范(统一)
ES Modules
基本特性
导入导出
<body>
<script type="module" src='app.js'></script>
</body>
import {name} from '/aaa.js'
console.log(name);
import
导出导入成员
浏览器环境 polyfill
ES module in Node
// node版本需大于8.5版本
import {name,age } from './module.mjs'
console.log(name,age);
import fs from 'fs'
fs.writeFileSync('./foo.txt','es module working')
// import _ from 'lodash'
// console.log(_.camelCase('ES module'));
// import {camelCase} from 'lodash' // 不能使用这种方式载入第三方模块
import { writeFileSync } from 'fs'
ES module in Node 与 commonJS交互
import mod from './common.js'
console.log(mod);
export const bar = 'bar'
ES module in Node 与 commonJS差异
// console.log(require);// 加载模块函数
// console.log(module);// 模块对象
// console.log(exports); // 导出对象别名
// console.log(__filename);// 当前文件的绝对路径
// console.log(__dirname); // 当前文件所在目录
// console.log(import.meta.url)
import {fileURLToPath} from 'url'
import {dirname} from 'path'
// const __filename = fileURLToPath(import.meta.url);
// const __dirname = dirname(__filename)
// console.log(__filename,__dirname);
ES module in Node 新版本支持
{"type":"module"}
ES module in Node Babel兼容方案
// 需要安装 @babel/node @babel/core @babel/preset-env
// 通过 yarn babel-node 文件执行 --preset=@babel/preset-env
// 或者
// .babelrc
// {
// "presets":['@babel/preset-env']
// }
// .babelrc
// {
// "plugins":[@babel/plugin-transform-modules-commonjs]
// }
模块打包工具(要解决的问题)
webpack 快速上手
webpack 配置文件
const path = require('path')
module.exports = {
entry:'./src/main.js',
output:{
filename:'bundle.js',
path:path.join(__dirname,'output')// 必须是绝对路径
}
}
webpack 工作模式 mode
mode:'development'
webpack 打包结果运行原理
webpack 资源模块加载
webpack 导入资源模块
import './main.css'
webpack 文件资源加载器
webpack URL加载器(data urls)
{
test:/\.png$/,
use:{
loader:'url-loader',
options:{
limit:10*1024
}
}
}
webpack 常用加载器分类
webpack 与 ES2015
{
test:/\.js$/,
loader:{
loader:'babel-loader',
options:{
presets:['@babel/preset-env']
}
}
webpack 加载资源的方式
{
test: /\.html$/,
use: {
loader: 'html-loader',
options: {
attributes: {
list: [
{
tag: 'img',
attribute: 'src',
type: 'src',
},
{
tag: 'a',
attribute: 'href',
type: 'src',
}
]
}
}
}
},
background-image: url('./1.png');
webpack 核心工作原理
webpack 开发一个loader
{
test:/\.md$/,
use:'./markdown-loader'
},
// ./markdown-loader.js
const marked = require('marked')
module.exports = source => {
// console.log(source)
const HTML = marked(source)
// 返回值就是最终被打包的内容
// return `module.exports=${JSON.stringify(HTML)}`
return HTML;
}
webpack 插件机制
webpack 自动清除输出目录
webpack 自动生成HTML插件
html-webpack-plugin
注意 :这里如果使用的是全局的webpack打包 会报错
Cannot find module 'webpack/lib/node/NodeTemplatePlugin'
使用npm link 链接到本地就行了
使用 多个new HtmlWebpackPlugin()实例 配置多个页面文件
copy-webpack-plugin 复制静态文件
webpack 开发一个插件
class MyPlugin {
apply(compiler) {
console.log('自定义插件');
compiler.hooks.emit.tap('MyPlugin', compilation => {
// compilation -->此次打包的上下文
for (const key in compilation.assets) {
// console.log(key);
// console.log(compilation.assets[key].source());
if (key.endsWith('.js')) {
const content = compilation.assets[key].source();
const withOutComment = content.replace(/\/\*\*+\*\//g,'')
compilation.assets[key] = {
source:()=>withOutComment,
size:()=>withOutComment.length
}
}
}
})
}
}
webpack 开发体验问题
webpack 自动编译
webpack --watch
webpack 自动刷新浏览器
webpack Dev server
webpack-dev-server --open
devServer:{
contentBase:'src'
},
proxy:{
'/api':{
target:'https://api.github.com',
pathRewrite:{
'^/api':''
},
changeOrigin:true
}
}
webpack sourcemap
webpack HMR
webpack 处理JS模块热替换
// ./main.js
// ... 原本的业务代码
module.hot.accept('./editor', () => {
// 当 ./editor.js 更新,自动执行此函数
console.log('editor 更新了~~')
})
webpack 处理图片模块热替换
// ./src/main.js
import logo from './icon.png'
// ... 其他代码
module.hot.accept('./icon.png', () => {
// 当 icon.png 更新后执行
// 重写设置 src 会触发图片元素重新加载,从而局部更新图片
img.src = logo
})
webpack 不同环境的配置文件
module.exports = (env,args)=>{
if(env==='production'){}
}
webpack DefinePlugin
new webpack.DefinePlugin({
API_BASE_URL:'"http://exmple.com"'
})
webpack Tree Shaking
optimization:{
usedExports:true,// 标记未引用代码
minimize:true,//移除未使用代码
},
{
test: /\.js$/,
loader: {
loader: 'babel-loader',
options: {
presets: [['@babel/preset-env',{modules:'commonjs'}]]
}
}
},
// modules:false// 确保不会开启esmodule的转换 Tree Shaking就不会失效
webpack 合并模块
webpack sideEffects副作用
optimization:{
sideEffects:true,//副作用
},
package.json中配置
sideEffects:false // 标识不是副作用
// package.json
sideEffects:['src/xxx','xxx.css']
webpack 代码分割
entry:{
index:'src/index.js',
album:'src/album.js'
},
output: {
filename: '[name].bundle.js',
path: path.join(__dirname, 'output'),// 必须是绝对路径
},
new HtmlWebpackPlugin({
chunks:['index']//指定页面引用
}),
optimization:{
splitChunks:{
chunks:'all'
}
}
import('./posts').then(({default:posts})=>{})
import(/* webpackChunkName:'posts' */'./posts').then(({default:posts})=>{})
webpack MiniCssExtractPlugin
mini-css-extract-plugin
new MiniCssExtractPlugin()
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
},
webpack OptimizationCssAssetsWebpackPlugin
optimize-css-assets-webpack-plugin
optimization:{
minimizer:[
new OptimizeCssAssetsWebpackPlugin(),
new TerserWebpackPlugin()
]
},
// 配置后 默认JS压缩失效,因为webpack认为我们要自定义压缩
// 需要手动开启new TerserWebpackPlugin() 插件为:terser-webpack-plugin
webpack 输出文件名hash
filename: '[name].[hash].js',
更为小巧,是一款ESM打包器
快速上手
yarn rollup ./src/index --format iife --file dist/bundle.js
配置文件
yarn rollup ./src/index --config rollup.config.js
使用插件(插件是rollup唯一的扩展途径)
rollup-plugin-json
import json from 'rollup-plugin-json'
export default{
input:'src/index.js',
output:{
file:'dist/bundle.js',
format:'cjs'
},
plugins:[
json()
]
}
加载npm模块
rollup-plugin-node-resolve
加载commonJS模块
rollup-plugin-commonjs
代码拆分
import('./logger').then()
多入口打包
input:['src/index.js','src/album.js'],
input:{ foo:'src/index.js', bar:'src/album.js' },
选用原则
parcel-bundler
yarn parcel src/index.html
yarn parcel build src/index.html
为什么需要规范化标准
哪里需要规范化
实施规范化的方法
ESLint
npm i eslint -D
npx eslint --init
npx eslint .\01-prepare.js --fix
module.exports = {
env: {//标记当前代码运行环境
browser: true,//浏览器环境
es2020: true
},
extends: [// 集成共享配置
'standard'
],
parserOptions: {//设置语法解析器
ecmaVersion: 11
},
rules: {
'no-alert':'error'
}
}
const script = () => {
return src('src/assets/scripts/*.js', { base: 'src' })
.pipe(plugins.eslint())
.pipe(plugins.eslint.format())
.pipe(plugins.eslint.failAfterError())
.pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
.pipe(dest('temp'))
.pipe(bs.reload({ stream: true }))
}
npm eslint --init
生成配置文件 {
test: /\.js$/,
exclude: /node_modules/,
use: 'eslint-loader',
enforce:'pre'
},
eslint-plugin-react
rules: {
'react/jsx-uses-react':2,
'react/jsx-uses-vars':2
},
plugins:[
'react'
]
// 或者
extends: [
'standard',
'plugin:react/recommended'
],
parser:'@typescript-eslint/parser'
Stylelint – css代码检测
stylelint-config-sass-guidelines
Pretier的使用
npm i prettier -D
npm prettier style.css --write
Git Hooks工作机制
ESLint结合Git Hooks
husky:{
"hooks":{
"pre-commit":"npm run test"
}
}
安装lint-stage
```javascript
"husky":{
"hooks":{
"pre-commit":"npm run precommit"
}
},
"lint-stage":{
"*.js":['eslint','git add']
}