webpack

129 阅读5分钟
命令

npx webpack

一般来说,调用 Mocha ,只能在项目脚本和 package.json 的scripts字段里面, 如果想在命令行下调用,必须像下面这样。

# 项目的根目录下执行
$ node-modules/.bin/mocha --version

npx 就是想解决这个问题,让项目内部安装的模块用起来更方便,只要像下面这样调用就行了。

$ npx mocha --version

npx 的原理很简单,就是运行的时候,会到node_modules/.bin路径和环境变量$PATH里面,检查命令是否存在。

由于 npx 会检查环境变量$PATH,所以系统命令也可以调用

注意,Bash 内置的命令不在$PATH里面,所以不能用。比如,cd是 Bash 命令,因此就不能用npx cd

打包支持模块化

打包运行
npx webpack写个index.html导入打包后的js
htmlWebpackPluginwebpack-dev-server
css打包
  • MiniCssExtractPlugin 抽离
  • autoprefixer postcss-loader 在样式的类前加浏览器前缀
  • optimize-css-assets-webpack-plugin 压缩
es6语法
  • @babel/preset-env 大集合
  • @balbel/code
  • @babel/plugin-transform-runtime 打包include语法
eslint
  • 官网上下载配置
  • 设置先执行enforce: 'pre'/post
配置命令
"build": "webpack",
"dev": "webpack-dev-server --open --port 3000 --hot "
全局变量(jquery cdn)
// 在文件中处理
import $ from 'expose-loader?$!jquery'
// 打包配置中匹配处理
{ 
	test: require.resolve('jquery'),
  use: 'expose-loader?$',
}
  
// 使用ProvidePlugin分别插入
const webpackPlugin = new webpack.ProvidePlugin({
 $: 'jquery'
})

//引入jquery会忽略掉(已经在cdn引入了)
externals: {
  jquery: '$'
}, 
图片

1.js import 图片 2.css 导入到js中,直接使用 3.html中引入图片html-withimg-loader

file-loader和url-loader

url-loader //做一个限制 当小于多少k 用base64来转化 base64文件可以减少http请求 但是比原文件大3分之1 // 否则用file-loader来产生真实的图片

打包分类和添加域名
options: {
  limit: 1, // 文件大小限制
  //输出的路径
  outputPath: 'img/', 
  //只在图片中有一个公共的路径
  publicPath: 'http:/111'
}
source-map源码映射(调试使用)

增加 devtool 源码映射 可以很方便的调试源代码

// 列是指定位到错误的代码列
 // 大 全
devtool:'source-map', 
// 不会单独生成一个文件 但会显示行和列
devtool: 'eval-source-map',
// 不会产生单独列 但会生成一个映射文件
devtool: 'cheap-module-source-map',
// 不会单独生成文件 集成在打包文件中 也不产生列
devtool: 'cheap-module-eval-source-map',
三个其他的小插件
// 1. cleanWebpackPlugin 
// 每次打包会把dist目录下的文件都删除 重新打包
// 2. copyWebpackPlugin
 //拷贝文件
 const copyPlugin = new copyWpackPlugin(
  //接受一个数组 可以多个文件
  [{from:'./doc',to:'./'}]
 )
// 3. bannerPlugin
// bannerPlugin 版权声明
const bannerPlugin = new webpack.BannerPlugin('make by hanke ,i will become success!')
// 前两个 需要第三方模块 第三个内置
webpack跨域
//跨域问题的设置
 devServer:{
  //这是 服务器为 /api/user
  /* proxy : {
   '/api':'http://localhost:3500'
  } */
  // /user的用法
  proxy: {
   // 1.重写的方式 把请求代理到express服务器上
   '/api': {
    target: 'http://localhost:3500',
    pathRewrite: {
     '/api':'/'
    }
   } 
  }
  //2.前端只想单纯模拟方法
  before(app){ //提供的方法 相当于钩子 
   //写这些代码就不存在跨域问题 
   app.get('/user',(req,res)=>{
    res.json({
     name: 'myname-before'
    })
   })
  }
  //3.有服务端,但是不用代理来处理 在服务器端开启webpack 端口用服务端端口
   /* 服务端代码
   //需要使用中间件webpack-dev-middleware
    let middle = require('webpack-dev-middleware')
    let config = require('./webpack.config.js')
    let compiler = webpack(config)
    app.use(middle(compiler))
   */
}
resolve配置
 resolve: {
  //指定解析的模块
  modules: [path.resolve('node_modules')],
  //或者用 mainFields 入口的字段 先找style 再找main
  // mainFiles: [],//入口文件的名字 默认找index.js
  mainFields: ['style','main'],
  //扩展名 可以省略 需配置 extensions 依次解析
  extensions: ['.js','.css','.json']
  //别名 如 vue的vue-runtime和那个@
  // alias: {
  //  bootstrap: 'bootstrap/dist/css/bootstrap.css'
  // }
 },
环境变量
// 判断开发环境的插件 DefinePlugin
const definePlugin = new webpack.DefinePlugin({
 DEV: JSON.stringify('production'),
 FLAG: 'true',
 EXPORESSION: '1+1'
})
区分环境
npm run build -- --config webpack.dev.js

webpack-merge
let {smart} = require('webpack-merge')
let base = require('./webpack.config.js')

module.exports = smart(base,{
 mode:'production'
})
忽略引入
//webpack自带的IgnorePlugin 忽略掉moment中locale引入的东西
const ignorePlugin = new webpack.IgnorePlugin(/\.\/locale/,/moment/)
import moment from 'moment'

//加入 ignorePlugin之后就不起作用了 
// moment.locale('zh-cn')

//自己手动引入所需要的语言包
import 'moment/locale/zh-cn'

let r = moment().endOf('day').fromNow()
动态引入链接库
//webpack自带的  config.js中引入打包好的库     
const dllReferencePlugin = new webpack.DllReferencePlugin({
 manifest: path.resolve(__dirname,'dist','manifest.json')
})

//webpack自带插件 打包成动态链接库 事先写好的webpack.config.xxx.js
//导出 manifest.json 以及 _dll_react.js
const dllPlugin = new webpack.DllPlugin({ //name==library
 name: '_dll_[name]',
 //manifest.json就是一个任务清单
 path: path.resolve(__dirname,'dist','manifest.json')
})
module.exports = {
  mode: 'development',
  entry: {
    // test: '.c/test.js'
    react: ['react','react-dom']
  },
  output: {
    filename: '_dll_[name].js', //打包后的文件名
    path: path.resolve(__dirname,'dist'),
    //指定 var a = '...'
    library: '_dll_[name]',
    //配置commonjs 会变成export["ab"] 配置umd会变成umd模式 可配置 commonjs var this 主要用var(默认就是)
    //braryTarget: 'var'
  },
  plugins: [
    dllPlugin
  ]
}

多线程打包
// 模块 happypack 来多线程打包webpack 进程(node中线程与进程关系) 打包文件会加快(文件很小时可能会变慢)
const Happypack = require('happypack')
// happyplugin配置
 const happyPlugin = new Happypack({
  id:'js',
  use: [{
   loader:'babel-loader',
   options: {
    presets: [
    '@babel/preset-env',
    '@babel/preset-react',
    ]
   }
  }]
 })
 rules:[
   {
    test: /\.js$/,
    //指定一个id 可能css也需要多线程打包
     use: 'Happypack/loader?id=js',
   }
 ]
webpack优化
 tree-shaking
scope hosting
import calc from './test'
// import 在生产环境下会自动清除没用的东西
// 相当于tree-shaking 没用代码自动删除
// import 可以 但是 require就不行
console.log(calc.sum(1,2))
// scope hosting 作用域提升 
 let a = 1
 let b = 2
 let c = 3
 let d = a+b+c //webpack会自动省略可以简化的代码
  console.log(d+'------') 
抽离公共代码
optimization: {
    splitChunks:{  //分割代码块
      cacheGrops:{  //缓存组
        common:{    //公共模块 
          chunks: 'initial',  //入口从哪找
          minSize: 0 , //大于0个字节
          minChunks: 0 //引用0次
        }
      },
      vendor: {  //抽离第三方模块
        priority: 1, //先抽离第三方模块
        test: de_modules/, //引入
        chunks: 'initial',  //入口从哪找
        minSize: 0 , //大于0个字节
        minChunks: 0 //引用0次
      }
    }
  },
热更新所需插件
// 热更新所需插件
const hotPlugin = new webpack.HotModuleReplacementPlugin()
const namePlugin = new webpack.NamedModulesPlugin() //打印名字
devServer:{
  //热更新
  hot: true,
  port: 3000,
  open: true,
  contentBase: './dist'
 },

告诉那个文件更新了

import str from './source.js'

console.log(str)

if(module.hot) {
 module.hot.accept('./source.js',()=>{
  //import只能写在页面的顶端
  let str =require('./source.js')
  console.log(str.default)
 })
}
tabable
  • 累加器
function getSum(total, num) {    
  return total + Math.round(num); 
} 
function myFunction(item) {    
  document.getElementById("demo").innerHTML = numbers.reduce(getSum, 0); 
}

将多个方法放在对象的属性中,调用call等时循环执行

// 同步调用
/*
SyncHook
SyncBailHook 中断
SyncWaterfallHook 下个参数为上个结果
SyncLoopHook 循环多次
*/
// 异步调用
/*
AsyncParallelHook 
// 方法
tapAsync callAsync(从参数中取最终函数,当调用一次时done一次计数,达到时调用最终函数) 
promise(会返回属性中返回的promise)
*/
webpack手写
npm link  // 链接到全局下,在全局node_module下生成命令当前目录下的快捷方式
npm link 文件名  // 'bin': {'命令':'文件名'},链接到当前node_module

// 1.先拿到入口文件路径和内容,
this.entry = config.entry
this.root = process.cwd() //表示 工作路径
let content = fs.readFileSync(modulePath,'utf-8')

// 2.通过ast解析内容中require(内容)和路径并替换成自己的方法和加’src’,返回解析编译后的内容和入口文件的附属模块数组
//babelon 把源码解析成AST
//@babel/traverse   遍历节点
//@babel/types   节点替换
//@babel/generator 生成
{
  'src/a.js':'let str = __webpack_require("./src\\a.js");\n console.log(str);'
}
['./src\\a.js']

// 3.通过附属模块数组递归调用3>>>1>>>2>>>3