清除输出目录:clean-webpack-plugin npm i -D clean-webpack-plugin
    自动生成目录:html-webpack-plugin npm i -D html-webpack-plugin
    复制静态资源:copy-webpack-plugin npm i -D copy-webpack-plugin
    开发服务器
    开发阶段,目前遇到的问题是打包、运行、调试过程过于繁琐,回顾一下我们的操作流程:

    1. 编写代码
      2. 控制台运行命令完成打包
      3. 打开页面查看效果
      4. 继续编写代码,回到步骤2
      并且,我们往往希望把最终生成的代码和页面部署到服务器上,来模拟真实环境。为了解决这些问题,webpack官方制作了一个单独的库:webpack-dev-server;它既不是plugin也不是loader;( 它并不会像真正的webpack打包,而是搭建了一个临时服务器环境,通过地址直接访问。它是开发阶段的,所以必须依赖开发环境。 )
      怎么用?1. 安装 2. 执行**`webpack-dev-server`**命令
      webpack-dev-server命令几乎支持所有的webpack命令参数,如--config--env等等,可以把它当作webpack命令使用;这个命令是专门为开发阶段服务的,真正部署的时候还是得使用webpack命令;当我们执行**webpack-dev-server**命令后,它做了以下操作:

    2. 内部执行webpack命令,传递命令参数
      2. 开启watch
      3. 注册hooks:类似于plugin,webpack-dev-server会向webpack中注册一些钩子函数,主要功能如下:
      a. 将资源列表(aseets)保存起来 b. 禁止webpack输出文件
      4. 用express开启一个服务器,监听某个端口,当请求到达后,根据请求的路径,给予相应的资源内容

    配置

    针对webpack-dev-server的配置,参考:https://www.webpackjs.com/configuration/dev-server/

    常见配置有:

    - port:配置监听端口
    - proxy:配置代理,常用于跨域访问
    - stats:配置控制台输出内容
    普通文件处理:(普通文件处理,这个文件里面也不是css代码,也不是js代码,而是像图片、字体……文件,之前我们用(copy-webpack-plugin)复制静态资源,静态资源里面有一些图片……,要原封不动copy到dist中,其中html页面当中有img.src是写死的。有的时候,它可能是js根据情况,往页面上添加,比方说在src中的assets文件中,通常我们根据 js 嵌入的资源都放到了assets中,在index.js页面中,const png = require(”./asssets/webpack.png”); if ( math.random < 0.5){ 用js添加一张图片let img = document.createElement(‘img’); img.src = png; document.body,appendChild(img); },我们希望的是导入的模块结果是一个可用的资源路径。但是这个是不符合要求的。因为这个模块webpack是把这个图片当做js处理的,到了抽象语法树的一分析就报错了,不是有效的js代码,因此这个时候打包是会遇到问题的。所以就要用到了loader,给我一个源代码返回另外一个源代码。file-loader就可以处理这样的一个问题)
    file-loader: 生成依赖的文件到输出目录,然后将模块文件设置为:导出一个路径\

    js<br />**//file-loader**<br />**function loader(source){**<br />** // source:文件内容(图片内容 buffer)**<br />** // 1. 生成一个具有相同文件内容的文件到输出目录**<br />** // 2. 返回一段代码 export default "文件名"**<br />**}**<br />
    url-loader:将依赖的文件转换为:导出一个base64格式的字符串

    js<br />**//file-loader**<br />**function loader(source){**<br />** // source:文件内容(图片内容 buffer)**<br />** // 1. 根据buffer生成一个base64编码**<br />** // 2. 返回一段代码 export default "base64编码"**<br />**}**<br />
    解决路径问题

    在使用file-loader或url-loader时,可能会遇到一个非常有趣的问题

    比如,通过webpack打包的目录结构如下:

    yaml<br />dist<br /> |—— img<br /> |—— a.png #file-loader生成的文件<br /> |—— scripts<br /> |—— main.js #export default "img/a.png"<br /> |—— html<br /> |—— index.html #<script src="../scripts/main.js" ></script><br />
    这种问题发生的根本原因:模块中的路径来自于某个loader或plugin,当产生路径时,loader或plugin只有相对于dist目录的路径,并不知道该路径将在哪个资源中使用,从而无法确定最终正确的路径; 面对这种情况,需要依靠webpack的配置publicPath解决
    webpack内置插件
    所有的webpack内置插件都作为webpack的静态属性存在的,使用下面的方式即可创建一个插件对象

    ```js
    const webpack = require(“webpack”)

    new webpack.插件名(options)
    ```
    DefinePlugin
    全局常量定义插件,使用该插件通常定义一些常量值,例如:

    js<br />**new webpack.DefinePlugin({**<br />** PI: `Math.PI`, // PI = Math.PI**<br />** VERSION: `"1.0.0"`, // VERSION = "1.0.0"**<br />** DOMAIN: JSON.stringify("duyi.com")**<br />**})**<br />
    这样一来,在源码中,我们可以直接使用插件中提供的常量,当webpack编译完成后,会自动替换为常量的值

    ## BannerPlugin
    它可以为每个chunk生成的文件头部添加一行注释,一般用于添加作者、公司、版权等信息

    js<br />**new webpack.BannerPlugin({**<br />** banner: `**<br />** hash:[hash]**<br />** chunkhash:[chunkhash]**<br />** name:[name]**<br />** author:yuanjin**<br />** corporation:duyi** ** `**<br />**})**<br />
    ## ProvidePlugin
    自动加载模块,而不必到处 import 或 require

    js<br />**new webpack.ProvidePlugin({**<br />** $: 'jquery',**<br />** _: 'lodash'**<br />**})**<br />
    然后在我们任意源码中:

    js<br />**$('#item'); // <= 起作用**<br />**_.drop([1, 2, 3], 2); // <= 起作用**<br />
    练习区域查询
    请求地址:http://yuanjin.tech:5100/api/local
    https://open.duyiedu.com/api/student/findAll?appkey=Diana_1602512479606
    method:GET

    query:(npm i -D query-string专门做地址栏参数解析的)
    - parentId: 可选,若不填,则查询所有省份,若填写省份id,则查询省份下的所有城市
    使用env区别环境的时候在package.json中配置的时候 需要这样 webpack —env abc

    1. 开发服务器
    2. webpack.config.js---
    3. const { CleanWebpackPlugin } = require("clean-webpack-plugin")
    4. const HtmlWebpackPlugin = require('html-webpack-plugin')
    5. module.exports = {
    6. mode: "development",
    7. devtool: "source-map",
    8. output: {
    9. filename: "scripts/[name].[chunkhash:5].js"
    10. },
    11. plugins: [
    12. new CleanWebpackPlugin(),
    13. new HtmlWebpackPlugin({
    14. template: "./public/index.html"
    15. })
    16. ],
    17. devServer: {
    18. port: 8000,
    19. open: true,
    20. proxy: { //代理规则
    21. "/api": {
    22. target: "http://open.duyiedu.com",
    23. changeOrigin: true //更改请求头中的host和origin
    24. }
    25. },
    26. stats: {
    27. modules: false,
    28. colors: true
    29. }
    30. },
    31. // stats: {
    32. // modules: false,
    33. // colors: true
    34. // }
    35. }
    36. ./src/index.js---
    37. const url = `/api/student/findAll?appkey=demo13_1545210570249`;
    38. fetch(url).then(resp => resp.json()).then(resp => {
    39. console.log(resp)
    40. })
    41. /* 我们访问的页面的主机名:http://localhost:8080 请求的地址是 https:developer.duyiedu.com……就是跨域了,协议
    42. 主机端口号都不一样。之前用的是jsonp 和 cros解决的跨域,但是都是需要服务器参与进来的,如果服务器没有解决这种问题呢?
    43. 在我们前端开发页面和js开发完成后往往会部署到同一个域中。比如:后台的服务器域,http://duyi.com,那么前端开发完成
    44. 后的放到服务器的域:http://duyi.com往往是一样的,最终访问的域是http://duyi.com,这样的话没有跨域问题了。但是现在
    45. 还没有开发完,还在开发阶段,这个跨域问题是在开发阶段发生了,实际上开发完了之后并不会产生这种问题,这个时候就因为是
    46. 同一个域可以直接用/api/student/findAll?appkey=demo13_1545210570249然后就不会出问题了;但是会找不到。所以就用
    47. 到了proxy */
    普通文件处理
    webpack.config.js---
      const { CleanWebpackPlugin } = require("clean-webpack-plugin")
      const HtmlWebpackPlugin = require('html-webpack-plugin')
      module.exports = {
          mode: "development",
          devtool: "source-map",
          output: {
              filename: "scripts/[name].[chunkhash:5].js"
          },
          module: {
              rules: [
                  {
                      test: /\.(png)|(gif)|(jpg)$/,
                      use: [{
                          loader: "url-loader",
                          options: {
                              // limit: false //不限制任何大小,所有经过loader的文件进行base64编码返回
                              limit: 10 * 1024, //只要文件不超过 100*1024 字节,则使用base64编码,否则,交给file-loader进行处理
                              name: "imgs/[name].[hash:5].[ext]"
                          }
                      }]
                  }
              ]
          },
          plugins: [
              new CleanWebpackPlugin(),
              new HtmlWebpackPlugin({
                  template: "./public/index.html"
              })
          ],
          devServer: {
              open: true
          },
          stats: {
              modules: false,
              colors: true
          }
      }
    ./src/index.js---
      //希望导入的模块结果是一个可用的资源路径
      import png from "./assets/webpack.png"
      console.log(png)
      var img = document.createElement("img");
      img.src = png;
      document.body.appendChild(img);
    
    webpack内置插件
    webpack.config.js---
      const webpack = require("webpack")
      module.exports = {
          mode: "development",
          devtool: "source-map",
          plugins: [
              new webpack.DefinePlugin({
                  PI: `Math.PI`, // const PI = Math.PI
                  VERSION: `"1.0.0"`, // VERSION = "1.0.0"
                  DOMAIN: JSON.stringify("duyi.com")  // DOMAIN = "duyi.com"
              }),
              new webpack.BannerPlugin({
                  banner: `    hash:[hash]
                            chunkhash:[chunkhash]
                            name:[name]
                            author:yuanjin
                            corporation:duyi `
              }),
              new webpack.ProvidePlugin({
                  $: 'jquery',
                  _: 'lodash'
              })
          ]
      }
    
    src/index.js---
      // console.log(PI);
      // console.log(VERSION);
      // console.log(DOMAIN);
    
      var r1 = $('#item'); // <= 起作用
      var r2 = _.drop([1, 2, 3], 2); // <= 起作用
      console.log(r1, r2);
    
    练习--区域查询
    webpack.config.js---
      const prodConfig = require('./webpack.prod') 
      const devConfig = require('./webpack.dev') 
      const baseConfig = require('./webpack.base') 
      module.exports = function (env) {
          // console.log({...baseConfig})
          if(env && env.abc){        
              return{
                  ...baseConfig,
                  ...prodConfig
              }
          }
          else{
              return{
                  ...baseConfig,
                  ...devConfig
              }
          }
      }
    
    webpack.dev.js---
      module.exports = {
        mode:"development",
        devServer:{
            open:true,
            openPage:'list.html',//用来打开指定的html
            proxy:{
                "/api":{
                    target:"https://open.duyiedu.com",
                    changeOrigin: true
                }
            }
        }    
    }
    
    webpack.prod.js---
      const { CleanWebpackPlugin } = require('clean-webpack-plugin');
      module.exports = {
          mode:"production",
          plugins:[
              new CleanWebpackPlugin(),//清除之前生成输出目录
          ]
      }
    
    webpack.base.js---
      const path = require('path');
      const HtmlWebpackPlugin = require('html-webpack-plugin');
      const CopyWebpackPlugin = require('copy-webpack-plugin');
      module.exports = {
          entry:{
              list: './src/list/index.js',
              detail: './src/detail/index.js'
          },
          output:{
              filename:"scripts/[name][chunkhash:5].js",
              path: path.resolve(process.cwd(), 'dist'),//这个是cleanwebpackplugin需要的
          },
          stats:{
              modules: false,//控制台中输出模块信息减少
              colors:true//控制台中的信息加重点颜色区分
          },
          plugins:[
              // new CleanWebpackPlugin(),//清除之前生成输出目录
              new HtmlWebpackPlugin({
                  template:"./public/list.html",
                  filename:"list.html",
                  chunks: ['list']
              }),
              new HtmlWebpackPlugin({//拿模板
                  template:"./public/detail.html",//copy模板的地址
                  filename:"detail.html",//生成模板之后的文件名字
                  chunks: ['detail']//规定引入的js文件 找到输出文件的名字
              }),
              new CopyWebpackPlugin({//用来复制文件的
                  patterns: [
                      { from: "./public", to: "./" },
                  ]
              })
          ]
      }
    
    ./src/detail/index.js--- 
        import $ from "jquery"
        import {getProvinces} from '../util/areaService';
        const dl = $("dl");
        getProvinces().then(res=>{
            for(const p of res.data){
                $("<dd>").text(`${p.address}`).appendTo(dl)
            }
        })
    
    ./src/list/index.js---
          import $ from "jquery"
          import {getProvinces} from '../util/areaService';
          console.log('aa')
          getProvinces().then(res=>{
              console.log(res.data)
              const ul = $(".provinces");
              for(const p of res.data){
                  const li = $("<li>").appendTo(ul);
                  const a = $("<a>").text(p.name).appendTo(li);
                  a.prop("href", `detail.html`)
    
              }
          })
    
    ./src/util/areaService.js---
        export async function getProvinces(){
            return await fetch('api/student/findAll?appkey=Diana_1602512479606').then(res=>res.json())
        }
    -----------------------------------------------------------------------------------------------------
    ./src/util/areaService.js---
      /* 得到所有的省份*/
        export async function getProvinces() {
            return await fetch("/api/local").then(resp => resp.json())
        }
        /*根据省份id得到所有的城市*/
        export async function getCities(parentId) {
            const url = `/api/local?parentId=${parentId}`;
            return await fetch(url).then(resp => resp.json())
        }
    
    ./src/list/index.js----
        import { getProvinces } from "@/util/areaService"
        import $ from "jquery"
        getProvinces().then(ps => {
            //ps:省份的数组
            const ul = $(".provinces");
            for (const p of ps) {
                const li = $("<li>").appendTo(ul);
                const a = $("<a>").text(p.simpleName).appendTo(li);
                a.prop("href", `detail.html?name=${p.areaName}&id=${p.id}`)
            }
        });
    
    ./src/detail/index.js---
      import { getCities } from "@/util/areaService"
      import qs from "query-string"
      import $ from "jquery"
      const parsed = qs.parse(location.search);
      $(".title").text(parsed.name)
      const dl = $("dl")
      getCities(parsed.id).then(cs=>{
          for(const c of cs){
              $("<dd>").text(c.simpleName).appendTo(dl)
          }
      })