webpack4搭建项目环境

5 篇文章 1 订阅

webpack发展史

  1. 在没有ajax和jQuery之前,前端是不存在打包这个说法的,js没有大规模使用,只做简单的时钟、mp3等效果,直接弄一个js文件引入就行
  2. 之后,人们开始使用iframe和flash等于服务器通信,因为这两种方式太过于tricky(棘手),直到google退出gmail的时候,人们发现了XMLHttpRequest,也就是AJAX,从此开始,前端出现了jquery等各种插件和库,js文件越来越多。
  3. 随着js做的事越来越多,js文件越来越大,U管理费用US等js文件压缩合并工具陆续诞生,但是也有很多问题,比如:
    1. 库和插件为了要给他人调用,肯定要找个地方注册,一般就是在 window 下申明一个全局的函数或对象。难保哪天用的两个库在全局用同样的名字,那就冲突了
    2. 库和插件如果还依赖其他的库和插件,就要告知使用人,需要先引哪些依赖库,那些依赖库也有自己的依赖库的话,就要先引依赖库的依赖库,以此类推
  4. 2009年,后端js发展,人们提出了CommonJS模块化规范,也就是exports和require语法。但是它并不适用于浏览器,require是同步的,堵塞js脚本的执行,所以人们基于CommonJS定义了AMD规范(2011年),使用异步回调的语法来并行下载多个依赖项,也就是define函数(必须返回值)。现在出了ES6,7之后,已经差不多淘汰AMD了
  5. 2012年,webpack诞生,Browserify同期诞生,但webpack比它的优点:多文件打包、可以关心所有文件的打包、对资源文件的加载支持完善、支持CommonJS、AMD和ES6模块规范等

简单搞一个SPA应用

页面搭建

  1. 接下来我们简单搞一个SPA应用,弄一个webpack配置
  2. 首先,本地肯定需要安装nodeJS,因为webpack是基于nodeJS的
  3. 然后,搭建项目目录,npm init初始化package.json文件,晒一下目录结构
     
    ├─ .eslintrc.js
    ├─ .gitignore
    ├─ dist
    │    ├─ index.html
    │    ├─ index.js
    │    └─ index.js.map
    ├─ index.html
    ├─ package-lock.json
    ├─ package.json
    ├─ src
    │    ├─ index.js
    │    ├─ router.js
    │    ├─ untils
    │    │    └─ axios.js
    │    └─ views
    │           ├─ about
    │           └─ home
    └─ webpack.config.js
  4. 接下来,需要安装依赖的包了
    1. 先安装eslint进行语法检查  
      npm install eslint eslint-config-enough babel-eslint eslint-loader --save-dev
      
      // package.json里面插入如下配置
      "eslintConfig": {
          "extends": "enough",
          "env": {
            "browser": true,
            "node": true
          }
        }

       

  5. 然后编辑index.html文件
     
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>首页</title>
    </head>
    <body>
      <div id="app">首页</div>
    </body>
    </html>
  6. 编辑src下的index.js文件
     
    // 引入 router
    import router from './router'
    
    // 启动 router
    router.start()
  7. 编辑src下的router.js文件
     
    // 引入页面文件
    import home from './views/home'
    import about from './views/about'
    
    const routes = {
      '/home': home,
      '/about': about
    }
    
    // Router 类,用来控制页面根据当前 URL 切换
    class Router {
      start () {
        // 点击浏览器后退 / 前进按钮时会触发 window.onpopstate 事件,我们在这时切换到相应页面
        // https://developer.mozilla.org/en-US/docs/Web/Events/popstate
        window.addEventListener('popstate', () => {
          this.load(window.location.pathname)
        })
    
        // 打开页面时加载当前页面
        this.load(window.location.pathname)
      }
    
      // 前往 path,变更地址栏 URL,并加载相应页面
      go (path) {
        // 变更地址栏 URL
        window.history.pushState({}, '', path)
        // 加载页面
        this.load(path)
      }
    
      // 加载 path 路径的页面
      load (path) {
        // 首页
        if (path === '/') path = '/home'
        // 创建页面实例
        const view = new routes[path]()
        // 调用页面方法,把页面加载到 document.body 中
        view.mount(document.body)
      }
    }
    
    // 导出 router 实例
    export default new Router()
    

     

  8. 然后在src的view下建立home和about两个文件夹,并在俩文件夹下新建index.js文件和style.css文件
     
    // home下的index.js举例
    // 引入 router
    import router from '../../router'
    
    // 引入 html 模板,会被作为字符串引入
    import template from '../../../index.html'
    
    // 引入 css, 会生成 <style> 块插入到 <head> 头中
    import './style.css'
    
    // 导出类
    export default class {
      mount (container) {
        document.title = 'foo'
        container.innerHTML = template
        container.querySelector('#app').addEventListener('click', () => {
          // 调用 router.go 方法加载 /bar 页面
          router.go('/about')
        })
      }
    }

     

webpack配置

  1. 安装webpack和它的插件 

    npm install webpack webpack-cli webpack-serve html-webpack-plugin html-loader css-loader style-loader file-loader url-loader --save-dev
  2. 安装babel以支持打包生成ES5  
     
    npm install @babel/core @babel/preset-env babel-loader --save-dev
  3. 在package.json里面添加配置项
     
    "babel": {
        "presets": ["env"]
      }
  4. 配置webpack
     
    const { resolve } = require('path')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const history = require('connect-history-api-fallback')
    const convert = require('koa-connect')
    
    // 使用 WEBPACK_SERVE 环境变量检测当前是否是在 webpack-server 启动的开发环境中
    const dev = Boolean(process.env.WEBPACK_SERVE)
    
    module.exports = {
      /*
      webpack 执行模式
      development:开发环境,它会在配置文件中插入调试相关的选项,比如 moduleId 使用文件路径方便调试
      production:生产环境,webpack 会将代码做压缩等优化
      */
      mode: dev ? 'development' : 'production',
    
      /*
      配置 source map
      开发模式下使用 cheap-module-eval-source-map, 生成的 source map 能和源码每行对应,方便打断点调试
      生产模式下使用 hidden-source-map, 生成独立的 source map 文件,并且不在 js 文件中插入 source map 路径,用于在 error report 工具中查看 (比如 Sentry)
      */
      devtool: dev ? 'cheap-module-eval-source-map' : 'hidden-source-map',
    
      // 配置页面入口 js 文件
      entry: './src/index.js',
    
      // 配置打包输出相关
      output: {
        // 打包输出目录
        path: resolve(__dirname, 'dist'),
    
        // 入口 js 的打包输出文件名
        filename: 'index.js'
      },
    
      module: {
        /*
        配置各种类型文件的加载器,称之为 loader
        webpack 当遇到 import ... 时,会调用这里配置的 loader 对引用的文件进行编译
        */
        rules: [
          {
            /*
            使用 babel 编译 ES6 / ES7 / ES8 为 ES5 代码
            使用正则表达式匹配后缀名为 .js 的文件
            */
            test: /\.js$/,
    
            // 排除 node_modules 目录下的文件,npm 安装的包不需要编译
            exclude: /node_modules/,
    
            /*
            use 指定该文件的 loader, 值可以是字符串或者数组。
            这里先使用 eslint-loader 处理,返回的结果交给 babel-loader 处理。loader 的处理顺序是从最后一个到第一个。
            eslint-loader 用来检查代码,如果有错误,编译的时候会报错。
            babel-loader 用来编译 js 文件。
            */
            use: ['babel-loader', 'eslint-loader']
          },
    
          {
            // 匹配 html 文件
            test: /\.html$/,
            /*
            使用 html-loader, 将 html 内容存为 js 字符串,比如当遇到
            import htmlString from './template.html';
            template.html 的文件内容会被转成一个 js 字符串,合并到 js 文件里。
            */
            use: 'html-loader'
          },
    
          {
            // 匹配 css 文件
            test: /\.css$/,
    
            /*
            先使用 css-loader 处理,返回的结果交给 style-loader 处理。
            css-loader 将 css 内容存为 js 字符串,并且会把 background, @font-face 等引用的图片,
            字体文件交给指定的 loader 打包,类似上面的 html-loader, 用什么 loader 同样在 loaders 对象中定义,等会下面就会看到。
            */
            use: ['style-loader', 'css-loader']
          },
    
          {
            /*
            匹配各种格式的图片和字体文件
            上面 html-loader 会把 html 中 <img> 标签的图片解析出来,文件名匹配到这里的 test 的正则表达式,
            css-loader 引用的图片和字体同样会匹配到这里的 test 条件
            */
            test: /\.(png|jpg|jpeg|gif|eot|ttf|woff|woff2|svg|svgz)(\?.+)?$/,
    
            /*
            使用 url-loader, 它接受一个 limit 参数,单位为字节(byte)
    
            当文件体积小于 limit 时,url-loader 把文件转为 Data URI 的格式内联到引用的地方
            当文件大于 limit 时,url-loader 会调用 file-loader, 把文件储存到输出目录,并把引用的文件路径改写成输出后的路径
    
            比如 views/foo/index.html 中
            <img src="smallpic.png">
            会被编译成
            <img src="https://img-blog.csdnimg.cn/2022010701245379171.png">
    
            而
            <img src="largepic.png">
            会被编译成
            <img src="/f78661bef717cf2cc2c2e5158f196384.png">
            */
            use: [
              {
                loader: 'url-loader',
                options: {
                  limit: 10000
                }
              }
            ]
          }
        ]
      },
    
      /*
      配置 webpack 插件
      plugin 和 loader 的区别是,loader 是在 import 时根据不同的文件名,匹配不同的 loader 对这个文件做处理,
      而 plugin, 关注的不是文件的格式,而是在编译的各个阶段,会触发不同的事件,让你可以干预每个编译阶段。
      */
      plugins: [
        /*
        html-webpack-plugin 用来打包入口 html 文件
        entry 配置的入口是 js 文件,webpack 以 js 文件为入口,遇到 import, 用配置的 loader 加载引入文件
        但作为浏览器打开的入口 html, 是引用入口 js 的文件,它在整个编译过程的外面,
        所以,我们需要 html-webpack-plugin 来打包作为入口的 html 文件
        */
        new HtmlWebpackPlugin({
          /*
          template 参数指定入口 html 文件路径,插件会把这个文件交给 webpack 去编译,
          webpack 按照正常流程,找到 loaders 中 test 条件匹配的 loader 来编译,那么这里 html-loader 就是匹配的 loader
          html-loader 编译后产生的字符串,会由 html-webpack-plugin 储存为 html 文件到输出目录,默认文件名为 index.html
          可以通过 filename 参数指定输出的文件名
          html-webpack-plugin 也可以不指定 template 参数,它会使用默认的 html 模板。
          */
          template: './src/index.html',
    
          /*
          因为和 webpack 4 的兼容性问题,chunksSortMode 参数需要设置为 none
          https://github.com/jantimon/html-webpack-plugin/issues/870
          */
          chunksSortMode: 'none'
        })
      ]
    }
    
    /*
    配置开发时用的服务器,让你可以用 http://127.0.0.1:8080/ 这样的 url 打开页面来调试
    并且带有热更新的功能,打代码时保存一下文件,浏览器会自动刷新。比 nginx 方便很多
    如果是修改 css, 甚至不需要刷新页面,直接生效。这让像弹框这种需要点击交互后才会出来的东西调试起来方便很多。
    
    因为 webpack-cli 无法正确识别 serve 选项,使用 webpack-cli 执行打包时会报错。
    因此我们在这里判断一下,仅当使用 webpack-serve 时插入 serve 选项。
    issue:https://github.com/webpack-contrib/webpack-serve/issues/19
    */
    if (dev) {
      module.exports.serve = {
        // 配置监听端口,默认值 8080
        port: 8080,
    
        // add: 用来给服务器的 koa 实例注入 middleware 增加功能
        add: app => {
          /*
          配置 SPA 入口
    
          SPA 的入口是一个统一的 html 文件,比如
          http://localhost:8080/foo
          我们要返回给它
          http://localhost:8080/index.html
          这个文件
          */
          app.use(convert(history()))
        }
      }
    }

     

  5. 启动和打包
    1. 用命令行启动  node_modules\.bin\webpack-serve webpack.config.js
    2. 用命令行打包  /node_modules/.bin/webpack-cli
  6. script配置
    1. 每次都写那么多有点麻烦,用script快捷命令入口启动,在package.json里面配置
      "scripts": {
          "dev": "webpack-serve webpack.config.js",
          "build": "webpack-cli"
        }

进阶配置

  1. 以上就完成了简单的配置,但是还是有很多点可以优化,比如 设置静态资源的 url 路径前缀、各个页面分开打包、第三方库和业务代码分开打包、输出的 entry 文件加上 hash、开发环境关闭 performance.hints、配置 favicon、开发环境允许其他电脑访问、打包时自定义部分参数、webpack-serve 处理路径带后缀名的文件的特殊规则、代码中插入环境变量、简化 import 路径、优化 babel 编译后的代码性能、使用 webpack 自带的 ES6 模块处理功能、使用 autoprefixer 自动创建 css 的 vendor prefixes

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值