從負一開始構建一個基於webpack4的項目

前言

做爲一個複製粘貼工程師,一直以來都是(可能只有我這樣 o(╥﹏╥)o )css

vue create hello-world
npx create-react-app hello-world
複製代碼

相似這樣的腳手架命令一頓操做,什麼Babel啊、Postcss、各類Loader、Eslint啊Uglifyjs都一把梭好了,然鵝到底這些是怎麼配置的,不知足需求的時候怎麼辦呢? 這些腳手架都是基於Webpack(Webpack是什麼?點我)的,最近在寫原生JS項目,沒有了腳手架就沒有Babel、autoprefixer、Uglifyjs了,那誰給我轉代碼,誰給我加瀏覽器前綴、誰給我壓縮代碼啊!複製粘貼工程師的自我修養告訴我不能這樣,這些活仍是讓別人幹比較好ヽ(✿゚▽゚)ノhtml

因而就開始了新的複製之旅vue

開始

先來複制一段,新建個項目,項目根目錄下npm init -y-y就是全yes了,至於yes了啥胸弟們能夠不-y試試 ︿( ̄︶ ̄)︿node

項目目錄下多了個package.json,裏面記錄了項目相關的信息。 react

基於Webpack咱們固然要安裝Webpack了webpack

npm i webpack webpack-cli -D
複製代碼

命令完成後,項目中多了一個 node_modules文件夾,該文件夾是用來存放項目中安裝的依賴包,之後項目依賴的包也都會在裏面。git

初始化項目目錄,新建src、dist、config以及index.html(html裏隨便寫點啥好比hello world等會打開了至少不是白的就行),還有src目錄下的入口文件index.js(空的便可)es6

初始化工做基本就完成了 webpack打包默認入口爲src/index.js, 默認打包模式爲 --mode development, 打包模式總共有兩種:github

  • mode development(開發環境)
  • mode production(生產環境)

如今能夠在package.json -> scripts 欄目 配置build的命令web

{
  "name": "test-webpack-bundler",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --mode production"
  },
  下面太長省略了...
}
複製代碼

而後執行npm run build

看已經打包成功了! 長征纔剛剛開始...

webpack配置工程師警告(๑•̀ㅂ•́)و✧

webpack配置之旅

開發環境

npm i webpack-dev-server html-webpack-plugin internal-ip -D 開發環境本地服務就靠webpack-dev-server了,生成html、自動插入js等就靠html-webpack-plugin了,局域網設備可經過IP訪問就靠internal-ip 在config目錄裏新建一個webpack.dev.js

又到了複製粘貼的時候啦

const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const packageConfig = require("../package.json");
const internalIp = require('internal-ip') // 藉助這個實現可用局域網IP訪問

const devWebpackConfig = {
  mode: "development",
  devtool:'#source-map',
  devServer: {
    port: 9527, // 指定端口號; 默認 8080
    hot: true, // 熱更新
    host: internalIp.v4.sync(), // 可經過局域網IP訪問,也能夠經過 localhost 訪問
    open: true, // 啓動本地服務後,自動打開頁面
    overlay: true, // 編譯器錯誤或警告時, 在瀏覽器中顯示全屏覆蓋; 默認false
    progress: true, // 是否將運行進度輸出到控制檯; 默認 false
    contentBase: path.resolve(__dirname, "dist"), // 告訴服務器從哪裏提供內容。只有在你想要提供靜態文件時才須要
    publicPath: "/",
    // 精簡終端輸出
    stats: {
      modules: false,
      children: false,
      chunks: false,
      chunkModules: false
    }
  },
  entry: ["./src/index.js"],
  plugins: [
    new HtmlWebpackPlugin({
      template: "index.html", // 指定模板html文件
      title: packageConfig.name, // html的title的值,這裏我從package.json裏取了
      inject: true, // 自動引入JS腳本的位置,默認值爲 true
    })
  ]
};

module.exports = devWebpackConfig;

複製代碼

devtool詳情看這裏 如今在package.json -> scripts 中配置dev的命令

"dev": "webpack-dev-server --config config/webpack.dev.js --color --progress"
複製代碼

如今npm run dev吧 胸弟們熟悉的不要不要的了吧,走你


沒問題咱們繼續,有問題···胸弟們百度一下吧

如今咱們就參考Vue Cli生成的項目整理目錄吧

  • assets 主要是圖片啊 圖標啊 字體啊 之類的
  • styles 就是css啦
  • utils 就是工具函數了 好比寫(複製)了個防抖啊、節流啊、時間格式化啊之類的扔進去,用的時候導入便可

webpack只認識js,圖標、字體、css等其餘的就須要各類loader拿給webpack,它才認識。

先搞定css吧,順便把sass和scss也搞了(less同理,找對應loader便可) 隨便寫幾句意思一下

index.html

<header class="flex-container header-wrapper">
      <h1 class="title">test-webpack4-bundler</h1>
      <div class="user-avatar-box">
        <img class="adaptive-img" src="./src/assets/uncle.jpg" alt="" />
      </div>
      <ul>
        <li class="list-item">1</li>
        <li class="list-item">2</li>
        <li class="list-item">3</li>
        <li class="list-item">4</li>
        <li class="list-item">5</li>
        <li class="list-item">6</li>
      </ul>
    </header>
複製代碼

src/index.js

import './styles/index.scss' // global css

複製代碼

src/styles/index.scss

@import "./header.scss";

.flex-container {
  display: flex;
  justify-content: center;
  align-items: center;
}

.adaptive-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

複製代碼

src/styles/header.scss

.header-wrapper {
  flex-direction: column;
  .title {
    color: rgb(65, 85, 28);
  }
  .user-avatar-box {
    width: 120px;
    height: 120px;
    overflow: hidden;
    border-radius: 50%;
  }
}
複製代碼

複製粘貼

npm i css-loader style-loader sass-loader sass postcss-loader autoprefixer -D
複製代碼

裝一堆 看名字也知道大概是幹什麼的了吧 postcss-loader配合autoprefixer就能夠自動加-webkit這些前綴了

(固然PostCSS還能幹不少事,想要了解的話點我

config/webpack.dev.js裏,和plugins同級配置loader

module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          "style-loader",
          "css-loader",
          "postcss-loader",
          {
            loader: "sass-loader",
            options: {
              implementation: require("sass")
              // 默認使用的node-sass,這樣配置就會使用dart-sass
            }
          }
          // webpack的規定,多個loader要倒着寫,好比scss文件先給sass-loader解析成css再給css-loader,以此類推
        ]
      }
    ]
  }
複製代碼

項目根目錄下建立兩個文件用來配置postcss-loader和autoprefixer

.browserslistrc

> 1%
last 2 versions
not ie <= 9

複製代碼

postcss.config.js

module.exports = {
  plugins: {
    autoprefixer: {}
  }
};

複製代碼

又能夠npm run dev了 已經看到咱們想要的樣子而且已經自動加了針對不一樣內核的前綴


css部分已經結束了,如今咱們寫點牛逼的代碼吧

utils/index.js

export function $(selector) {
  return document.querySelector(selector);
}

複製代碼

src/index.js

import "./styles/index.scss"; // global css
import { $ } from "./utils";
import { resolve } from "path";

window.onload = () => {
  const showText = "守護姨父的微笑";
  setTimeout(() => {

  }, 1000);
  const changeTitle = () => {
    let myPromise = new Promise((resolve, reject) => {
      resolve();
    });
    return myPromise;
  };
  changeTitle().then(()=>{
    $(".title").innerHTML = `咱們要${showText}`;
    const lists = [...document.querySelectorAll(".list-item")];
    lists.forEach(element => {
      console.log(element);
    });
    let [a, b, c] = ["索尼好!退果報平安", 2, 3];
    console.log(a);
    $(".title").innerHTML = `咱們要${showText}${a}`;
  })
};

複製代碼

好了咱們寫了箭頭函數、模板字符串、const聲明、Promise都是es6的語法,某些不現代的瀏覽器不支持,因此咱們須要Babel老弟幫幫咱們

複製粘貼

npm i babel-loader @babel/core @babel/preset-env @babel/runtime @babel/plugin-transform-runtime @babel/plugin-syntax-dynamic-import -D
複製代碼

src/index.js 頭部引入墊片

import "@babel/polyfill";
複製代碼

項目根目錄下新建.babelrc

{
  "presets": ["@babel/preset-env"],
  "plugins": [
    "@babel/plugin-transform-runtime"
  ]
}

複製代碼

config/webpack.dev.js 裏module>rules下增長一個loader

{
        test: /\.js$/,
        use: ["babel-loader"],
        exclude: /node_modules/
      },
複製代碼

config/webpack.dev.js entry加入 @babel/polyfill

entry: ["@babel/polyfill","./src/index.js"]
複製代碼

package.json -> scripts build

"build": "webpack --config config/webpack.dev.js --mode production --color --progress"
複製代碼

npm run build走一波

es6的語法都沒有了,該有的墊片也有了

(babel-polyfill和babel-runtime的關係和區別大概能夠看這裏)

好像大概是弄完了?等等,打包出來的html文件圖片引用路徑好像不對,沒hash值迭代了緩存不得搞死咱們啊,那麼下一輪複製粘貼又要開始了。


生產環境

開發環境大概就這麼樣了吧,針對生產環境咱們須要再搞點東西了 先複製一份webpack.dev.js,叫webpack.prod.js,做爲生產環境的webpack配置

裝,分別是解決js和html裏的文件路徑問題

npm i url-loader file-loader html-withimg-loader -D
複製代碼

而後刪除開發服務器,

config/webpack.prod.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const packageConfig = require("../package.json");

const prodWebpackConfig = {
  mode: "production",
  devtool: false,
  entry: ["@babel/polyfill", "./src/index.js"],
  output: {
    path: path.resolve(__dirname, "../dist"),
    filename: path.posix.join("static", "js/[name].[chunkhash].js"),
    chunkFilename: path.posix.join("static", "js/[id].[chunkhash].js")
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: ["babel-loader"],
        exclude: /node_modules/
      },
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          "style-loader",
          "css-loader",
          "postcss-loader",
          {
            loader: "sass-loader",
            options: {
              implementation: require("sass")
              // 默認使用的node-sass,這樣配置就會使用dart-sass
            }
          }
          // webpack的規定,多個loader要倒着寫,好比scss文件先給sass-loader解析成css再給css-loader,以此類推
        ]
      },
      {
        test: /\.(htm|html)$/,
        loader: "html-withimg-loader"
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: "url-loader",
        options: {
          limit: 10000,
          name: path.posix.join("static", "img/[name].[hash:7].[ext]")
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: "url-loader",
        options: {
          limit: 10000,
          name: path.posix.join("static", "fonts/[name].[hash:7].[ext]")
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "index.html", // 指定模板html文件
      title: packageConfig.name, // html的title的值,這裏我從package.json裏取了
      inject: true, // 自動引入JS腳本的位置,默認值爲 true
      minify: {
        minifycss: true, // 壓縮css
        minifyJS: true, // 壓縮JS
        removeComments: true, // 去掉註釋
        collapseWhitespace: true, // 去掉空行
        removeRedundantAttributes: true, // 去掉多餘的屬性
        removeAttributeQuotes:true, // 刪除不須要引號的屬性值
        removeEmptyAttributes: true // 去掉空屬性
      }
    })
  ]
};

module.exports = prodWebpackConfig;

複製代碼

package.json -> scripts build 該用生產環境的配置build了

"build": "webpack --config config/webpack.prod.js --mode production --color --progress"
複製代碼

npm run build走一波

能夠看到,html壓縮過了,img路徑也正確了,同時目錄結構也整齊多了,文件也帶了hash值

結尾

大致上完成了,後續還有一些優化,好比用指定的插件去壓縮JS,CSS抽離成單個文件並優化,將根目錄下的static下靜態資源copy到打包目錄下等,單獨抽離第三方庫等,就不一一說了,主要寫這玩意太累了。。。大佬們好牛逼。。。。真的

若是有哪裏有問題歡迎大佬們告訴我!感恩!

附上這個項目的地址 裏面包含了比較完整的配置,至少個人項目裏大概就是這樣了。

相關文章
相關標籤/搜索