成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

通用、封裝、簡化 webpack 配置

PingCAP / 2777人閱讀

摘要:通用封裝簡化配置現(xiàn)在,基本上前端的項(xiàng)目打包都會用上,因?yàn)樘峁┝藷o與倫比強(qiáng)大的功能和生態(tài)。簡化配置的一種方式是使用社區(qū)封裝好的庫,比如。封裝了的一些基礎(chǔ)配置,然后暴露一些額外配置的接口,并附加本地?cái)?shù)據(jù)模擬功能,詳情可以參考主頁。

通用、封裝、簡化 webpack 配置

現(xiàn)在,基本上前端的項(xiàng)目打包都會用上 webpack,因?yàn)?webpack 提供了無與倫比強(qiáng)大的功能和生態(tài)。但在創(chuàng)建一個(gè)項(xiàng)目的時(shí)候,總是免不了要配置 webpack,很是麻煩。

簡化 webpack 配置的一種方式是使用社區(qū)封裝好的庫,比如 roadhog。roadhog 封裝了 webpack 的一些基礎(chǔ)配置,然后暴露一些額外配置的接口,并附加本地?cái)?shù)據(jù)模擬功能(mock),詳情可以參考 roadhog 主頁。

另一種方式是自己封裝 webpack,這樣做自己能夠更好的掌控項(xiàng)目。

1. 要封裝哪些功能

一般搭建一個(gè)項(xiàng)目至少需要兩種功能:本地開發(fā)調(diào)試、構(gòu)建產(chǎn)品代碼。

其他的諸如測試、部署到服務(wù)器、代碼檢查、格式優(yōu)化等功能則不在這篇文章講解范圍,如果有意了解,可以查看我的其他文章。

2. 基礎(chǔ)配置 2.1 目錄結(jié)構(gòu)(示例,配合后面的代碼講解)
package.json
dev.js                       # 本地開發(fā)腳本
build.js                     # 產(chǎn)品構(gòu)建腳本
analyze.js                   # 模塊大小分析(可選)

# 單頁面結(jié)構(gòu)
src/                         # 源代碼目錄
  - index.js                 # js 入口文件
  - index.html               # html 入口文件
  - ...                      # 其他文件

# 多頁面結(jié)構(gòu)
src/                         # 源代碼目錄
  - home/                    # home 頁面工作空間
    - index.js               # home 頁面 js 入口文件
    - index.html             # home 頁面 html 入口文件
    - ...                    # home 頁面其他文件
    
  - explore/                 # explore 頁面工作空間
    - index.js               # explore 頁面 js 入口文件
    - index.html             # explore 頁面 html 入口文件
    - ...                    # explore 頁面其他文件 
     
  - about/                   # about 目錄
    - company                # about/company 頁面工作空間
      - index.js             # about/company 頁面 js 入口文件
      - index.html           # about/company 頁面 html 入口文件
      - ...                  # about/company 頁面其他文件
      
    - platform               # about/platform 頁面工作空間
      - index.js             # about/platform 頁面 js 入口文件
      - index.html           # about/platform 頁面 html 入口文件
      - ...                  # about/platform 頁面其他文件    
  
  - ...                      # 更多頁面        
2.2 基礎(chǔ) npm 包
# package.json

"devDependencies": {
  "@babel/core": "^7.1.2",                  # babel core       
  "@babel/plugin-syntax-dynamic-import": "^7.0.0",         # import() 函數(shù)支持
  "@babel/plugin-transform-react-jsx": "^7.0.0",           # react jsx 支持
  "@babel/preset-env": "^7.1.0",            # es6+ 轉(zhuǎn) es5
  "@babel/preset-flow": "^7.0.0",           # flow 支持
  "@babel/preset-react": "^7.0.0",          # react 支持
  "autoprefixer": "^9.1.5",                 # css 自動添加廠家前綴 -webkit-, -moz-
  "babel-loader": "^8.0.4",                 # webpack 加載 js 的 loader
  "babel-plugin-component": "^1.1.1",       # 如果使用 element ui,需要用到這個(gè)
  "babel-plugin-flow-runtime": "^0.17.0",   # flow-runtime 支持 
  "babel-plugin-import": "^1.9.1",          # 如果使用 ant-design,需要用到這個(gè)
  "browser-sync": "^2.24.7",                # 瀏覽器實(shí)例組件,用于本地開發(fā)調(diào)試
  "css-loader": "^1.0.0",                   # webpack 加載 css 的 loader
  "chalk": "^2.4.1",                        # 讓命令行的信息有顏色
  "file-loader": "^2.0.0",                  # webpack 加載靜態(tài)文件的 loader
  "flow-runtime": "^0.17.0",                # flow-runtime 包
  "html-loader": "^0.5.5",                  # webpack 加載 html 的 loader
  "html-webpack-include-assets-plugin": "^1.0.5",          # 給 html 文件添加額外靜態(tài)文件鏈接的插件
  "html-webpack-plugin": "^3.2.0",          # 更方便操作 html 文件的插件
  "less": "^3.8.1",                         # less 轉(zhuǎn) css
  "less-loader": "^4.1.0",                  # webpack 加載 less 的 loader
  "mini-css-extract-plugin": "^0.4.3",      # 提取 css 多帶帶打包
  "minimist": "^1.2.0",                     # process.argv 更便捷處理
  "node-sass": "^4.9.3",                    # scss 轉(zhuǎn) css
  "optimize-css-assets-webpack-plugin": "^5.0.1",          # 優(yōu)化 css 打包,包括壓縮
  "postcss-loader": "^3.0.0",               # 對 css 進(jìn)行更多操作,比如添加廠家前綴
  "sass-loader": "^7.1.0",                  # webpack 加載 scss 的 loader
  "style-loader": "^0.23.0",                # webpack 加載 style 的 loader
  "uglifyjs-webpack-plugin": "^2.0.1",      # 壓縮 js 的插件
  "url-loader": "^1.1.1",                   # file-loader 的升級版
  "vue-loader": "^15.4.2",                  # webpack 加載 vue 的 loader
  "vue-template-compiler": "^2.5.17",       # 配合 vue-loader 使用的 
  "webpack": "^4.20.2",                     # webpack 模塊
  "webpack-bundle-analyzer": "^3.0.2",      # 分析當(dāng)前打包各個(gè)模塊的大小,決定哪些需要多帶帶打包
  "webpack-dev-middleware": "^3.4.0",       # webpack-dev-server 中間件
  "webpack-hot-middleware": "^2.24.2"       # 熱更新中間件
}
2.3 基本命令
# package.json

"scripts": {
  "dev": "node dev.js",
  "build": "node build.js",
  "analyze": "node analyze.js",
}
npm run dev                                 # 開發(fā)
npm run build                               # 構(gòu)建
npm run analyze                             # 模塊分析

如果需要支持多入口構(gòu)建,在命令后面添加參數(shù):

npm run dev -- home                         # 開發(fā) home 頁面 
npm run analyze -- explore                  # 模塊分析 explore 頁面 

# 構(gòu)建多個(gè)頁面 
npm run build -- home explore about/* about/all --env test/prod  

home, explore 確定構(gòu)建的頁面;about/*, about/allabout 目錄下所有的頁面;all, * 整個(gè)項(xiàng)目所有的頁面

有時(shí)候可能還會針對不同的服務(wù)器環(huán)境(比如測試機(jī)、正式機(jī))做出不同的構(gòu)建,可以在后面加參數(shù)

-- 用來分割 npm 本身的參數(shù)與腳本參數(shù),參考 npm - run-script 了解詳情

2.4 dev.js 配置

開發(fā)一般用需要用到下面的組件:

webpack

webpack-dev-server 或 webpack-dev-middleware

webpack-hot-middleware

HotModuleReplacementPlugin

browser-sync

const minimist = require("minimist");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const devMiddleWare = require("webpack-dev-middleware");
const hotMiddleWare = require("webpack-hot-middleware");
const browserSync = require("browser-sync");
const VueLoaderPlugin = require("vue-loader/lib/plugin");

const { HotModuleReplacementPlugin } = webpack;

const argv = minimist(process.argv.slice(2));

const page = argv._[0];

 // 單頁面
const entryFile = `${__dirname}/src/index.js`;
// 多頁面 
const entryFile = `${__dirname}/src/${page}/index.js`; 

// 編譯器對象
const compiler = webpack({
  entry: [
    "webpack-hot-middleware/client?reload=true",      // 熱重載需要
    entryFile,
  ],
  output: {
    path: `${__dirname}/dev/`,                        // 打包到 dev 目錄
    filename: "index.js",
    publicPath: "/dev/",
  },
  plugins: [
    new HotModuleReplacementPlugin(),                 // 熱重載插件
    new HtmlWebpackPlugin({                           // 處理 html
      // 單頁面
      template: `${__dirname}/src/index.html`,
      // 多頁面
      template: `${__dirname}/src/${page}/index.html`,
    }),
    new VueLoaderPlugin(),                            // vue-loader 所需
  ],
  module: {
    rules: [
      {                                               // js 文件加載器
        loader: "babel-loader",
        exclude: /node_modules/,
        options: {
          presets: ["@babel/preset-env", "@babel/preset-react"],
          plugins: [
            "@babel/plugin-transform-react-jsx",
            "@babel/plugin-syntax-dynamic-import",
          ],
        },
        test: /.(js|jsx)$/,
      },
      {                                               // css 文件加載器
        loader: "style-loader!css-loader",
        test: /.css$/,
      },
      {                                               // less 文件加載器
        loader: "style-loader!css-loader!less-loader",
        test: /.less$/,
      },
      {                                               // scss 文件加載器
        loader: "style-loader!css-loader!sass-loader",
        test: /.(scss|sass)$/,
      },
      {                                               // 靜態(tài)文件加載器
        loader: "url-loader",
        test: /.(gif|jpg|png|woff|woff2|svg|eot|ttf|ico)$/,
        options: {
          limit: 1,
        },
      },
      {                                               // html 文件加載器
        loader: "html-loader",
        test: /.html$/,
        options: {
          attrs: ["img:src", "link:href"],
          interpolate: "require",
        },
      },
      {                                               // vue 文件加載器
        loader: "vue-loader",
        test: /.vue$/,
      },
    ],
  },
  resolve: {
    alias: {},                                        // js 配置別名   
    modules: [`${__dirname}/src`, "node_modules"],    // 模塊尋址基路徑
    extensions: [".js", ".jsx", ".vue", ".json"],     // 模塊尋址擴(kuò)展名
  },
  devtool: "eval-source-map",                         // sourcemap 
  mode: "development",                                // 指定 webpack 為開發(fā)模式
});

// browser-sync 配置
const browserSyncConfig = {
  server: {
    baseDir: `${__dirname}/`,                         // 靜態(tài)服務(wù)器基路徑,可以訪問項(xiàng)目所有文件 
  },
  startPath: "/dev/index.html",                       // 開啟服務(wù)器窗口時(shí)的默認(rèn)地址
};

// 添加中間件
browserSyncConfig.middleware = [
  devMiddleWare(compiler, {
    stats: "errors-only",
    publicPath: "/dev/",
  }),
  hotMiddleWare(compiler),
];

browserSync.init(browserSyncConfig);                  // 初始化瀏覽器實(shí)例,開始調(diào)試開發(fā)
2.5 build.js 配置

構(gòu)建過程中,一般會有這些過程:

提取樣式文件,多帶帶打包、壓縮、添加瀏覽器廠家前綴

js 在產(chǎn)品模式下進(jìn)行打包,并生成 sourcemap 文件

html-webpack-plugin 自動把打包好的樣式文件與腳本文件引用到 html 文件中,并壓縮

對所有資源進(jìn)行 hash 化處理(可選)

const minimist = require("minimist");
const webpack = require("webpack");
const chalk = require("chalk");
const autoprefixer = require("autoprefixer");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const VueLoaderPlugin = require("vue-loader/lib/plugin");

const {yellow, red} = chalk;

const argv = minimist(process.argv.slice(2));

const pages = argv._; // ["home", "explore", "about/*", "about/all"]
const allPages = getAllPages(pages); // 根據(jù) page 中的 `*, all` 等關(guān)鍵字,獲取所有真正的 pages

// 單頁面,只有一個(gè)入口,所以只有一個(gè)配置文件
const config = { ... }; 

// 多頁面,多個(gè)入口,所有有多個(gè)配置文件
const configs = allPages.map(page => ({
  // 單頁面
  entry: `${__dirname}/src/index.js`,                 // js 入口文件
  // 多頁面
  entry: `${__dirname}/src/${page}/index.js`,         // js 入口文件
  output: {
    path: `${__dirname}/dist/`,                       // 輸出路徑
    filename: "[chunkhash].js",                       // 輸出文件名,這里完全取 hash 值來命名
    hashDigestLength: 32,                             // hash 值長度
    publicPath: "/dist/",
  },
  plugins: [
    new MiniCssExtractPlugin({                        // 提取所有的樣式文件,多帶帶打包
      filename: "[chunkhash].css",                    // 輸出文件名,這里完全取 hash 值來命名
    }),
    new HtmlWebpackPlugin({
      // 單頁面
      template: `${__dirname}/src/index.html`,        // html 入口文件
      // 多頁面
      template: `${__dirname}/src/${page}/index.html`,// html 入口文件
      minify: {                                       // 指定如果壓縮 html 文件
        removeComments: !0,
        collapseWhitespace: !0,
        collapseBooleanAttributes: !0,
        removeEmptyAttributes: !0,
        removeScriptTypeAttributes: !0,
        removeStyleLinkTypeAttributes: !0,
        minifyJS: !0,
        minifyCSS: !0,
      },
    }),
    new VueLoaderPlugin(),                            // vue-loader 所需
    new OptimizeCssAssetsPlugin({                     // 壓縮 css
      cssProcessorPluginOptions: {
        preset: ["default", { discardComments: { removeAll: true } }],
      },
    }),
    
    // webpack 打包的 js 文件是默認(rèn)壓縮的,所以這里不需要再額外添加 uglifyjs-webpack-plugin
  ],
  module: {
    rules: [
      {                                               // js 文件加載器,與 dev 一致
        loader: "babel-loader",
        exclude: /node_modules/,
        options: {
          presets: ["@babel/preset-env", "@babel/preset-react"],
          plugins: [
            "@babel/plugin-transform-react-jsx",
            "@babel/plugin-syntax-dynamic-import",
          ],
        },
        test: /.(js|jsx)$/,
      },
      {                                               // css 文件加載器,添加了瀏覽器廠家前綴
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          {
            loader: "postcss-loader",
            options: {
              plugins: [
                autoprefixer({
                  browsers: [
                    "> 1%",
                    "last 2 versions",
                    "Android >= 3.2",
                    "Firefox >= 20",
                    "iOS 7",
                  ],
                }),
              ],
            },
          },
        ],
        test: /.css$/,
      },
      {                                               // less 文件加載器,添加了瀏覽器廠家前綴
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          {
            loader: "postcss-loader",
            options: {
              plugins: [
                autoprefixer({
                  browsers: [
                    "> 1%",
                    "last 2 versions",
                    "Android >= 3.2",
                    "Firefox >= 20",
                    "iOS 7",
                  ],
                }),
              ],
            },
          },
          "less-loader",
        ],
        test: /.less$/,
      },
      {                                               // scss 文件加載器,添加了瀏覽器廠家前綴
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          {
            loader: "postcss-loader",
            options: {
              plugins: [
                autoprefixer({
                  browsers: [
                    "> 1%",
                    "last 2 versions",
                    "Android >= 3.2",
                    "Firefox >= 20",
                    "iOS 7",
                  ],
                }),
              ],
            },
          },
          "sass-loader",
        ],
        test: /.(scss|sass)$/,
      },
      {                                               // 靜態(tài)文件加載器,與 dev 一致
        loader: "url-loader",
        test: /.(gif|jpg|png|woff|woff2|svg|eot|ttf|ico)$/,
        options: {
          limit: 1,
        },
      },
      {                                               // html 文件加載器,與 dev 一致
        loader: "html-loader",
        test: /.html$/,
        options: {
          attrs: ["img:src", "link:href"],
          interpolate: "require",
        },
      },
      {                                               // vue 文件加載器,與 dev 一致
        loader: "vue-loader",
        test: /.vue$/,
      },
    ],
  },
  resolve: {
    alias: {},                                        // js 配置別名   
    modules: [`${__dirname}/src`, "node_modules"],    // 模塊尋址基路徑
    extensions: [".js", ".jsx", ".vue", ".json"],     // 模塊尋址擴(kuò)展名
  },
  devtool: "source-map",                              // sourcemap 
  mode: "production",                                 // 指定 webpack 為產(chǎn)品模式
}));

// 執(zhí)行一次 webpack 構(gòu)建
const run = (config, cb) => {
  webpack(config, (err, stats) => {
    if (err) {
      console.error(red(err.stack || err));
      if (err.details) {
        console.error(red(err.details));
      }
      process.exit(1);
    }
  
    const info = stats.toJson();
  
    if (stats.hasErrors()) {
      info.errors.forEach(error => {
        console.error(red(error));
      });
      process.exit(1);
    }
  
    if (stats.hasWarnings()) {
      info.warnings.forEach(warning => {
        console.warn(yellow(warning));
      });
    }
    
    // 如果是多頁面,需要把 index.html => `${page}.html`
    // 因?yàn)槊總€(gè)頁面導(dǎo)出的 html 文件都是 index.html 如果不重新命名,會被覆蓋掉
    
    if(cb) cb();
  });
};

// 單頁面
run(config);

// 多頁面
let index = 0;
// go on
const goon = () => {
  run(configs[index], () => {
    index += 1;

    if (index < configs.length) goon();
  });
};

goon();
2.6 analyze.js 配置

const minimist = require("minimist");
const chalk = require("chalk");
const webpack = require("webpack");
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
const VueLoaderPlugin = require("vue-loader/lib/plugin");

const {yellow, red} = chalk;

const argv = minimist(process.argv.slice(2));

const page = argv._[0];

 // 單頁面
const entryFile = `${__dirname}/src/index.js`;
// 多頁面 
const entryFile = `${__dirname}/src/${page}/index.js`; 

const config = {
  entry: entryFile,
  output: {
    path: `${__dirname}/analyze/`,                    // 打包到 analyze 目錄
    filename: "index.js",
  },
  plugins: [
    new VueLoaderPlugin(),                            // vue-loader 所需
    new BundleAnalyzerPlugin(),                       // 添加插件 
  ],
  module: {
    rules: [
      {                                               // js 文件加載器
        loader: "babel-loader",
        exclude: /node_modules/,
        options: {
          presets: ["@babel/preset-env", "@babel/preset-react"],
          plugins: [
            "@babel/plugin-transform-react-jsx",
            "@babel/plugin-syntax-dynamic-import",
          ],
        },
        test: /.(js|jsx)$/,
      },
      {                                               // css 文件加載器
        loader: "style-loader!css-loader",
        test: /.css$/,
      },
      {                                               // less 文件加載器
        loader: "style-loader!css-loader!less-loader",
        test: /.less$/,
      },
      {                                               // scss 文件加載器
        loader: "style-loader!css-loader!sass-loader",
        test: /.(scss|sass)$/,
      },
      {                                               // 靜態(tài)文件加載器
        loader: "url-loader",
        test: /.(gif|jpg|png|woff|woff2|svg|eot|ttf|ico)$/,
        options: {
          limit: 1,
        },
      },
      {                                               // html 文件加載器
        loader: "html-loader",
        test: /.html$/,
        options: {
          attrs: ["img:src", "link:href"],
          interpolate: "require",
        },
      },
      {                                               // vue 文件加載器
        loader: "vue-loader",
        test: /.vue$/,
      },
    ],
  },
  resolve: {
    alias: {},                                        // js 配置別名   
    modules: [`${__dirname}/src`, "node_modules"],    // 模塊尋址基路徑
    extensions: [".js", ".jsx", ".vue", ".json"],     // 模塊尋址擴(kuò)展名
  },
  mode: "production",                                 // 指定 webpack 為產(chǎn)品模式
};

webpack(config, (err, stats) => {
  if (err) {
    console.error(red(err.stack || err));
    if (err.details) {
      console.error(red(err.details));
    }
    process.exit(1);
  }

  const info = stats.toJson();

  if (stats.hasErrors()) {
    info.errors.forEach(error => {
      console.error(red(error));
    });
    process.exit(1);
  }

  if (stats.hasWarnings()) {
    info.warnings.forEach(warning => {
      console.warn(yellow(warning));
    });
  }
});
2.7 擴(kuò)展配置

你可以根據(jù)需要擴(kuò)展配置,比如添加插件、加載器等,比如:

provide-plugin 可以提供一些全局模塊的導(dǎo)出,比如 jquery

define-plugin 可以動態(tài)定義一些全局變量

css-loader 可以配置成 css-modules

如果某個(gè)頁面導(dǎo)出 js bundle 很大,想分割成多個(gè)文件,可以使用 dll-plugin、split-chunks-plugin

如果想在命令行顯示構(gòu)建的進(jìn)度,可以使用 progress-plugin

3. 封裝

上面的代碼可以封裝成一個(gè)全局命令,比如 lila,運(yùn)行上面的命令就可以更簡潔:

lila dev home                               # 開發(fā) home 頁面 
lila analyze explore                        # 模塊分析 explore 頁面 

# 構(gòu)建多個(gè)頁面 
lila build home explore about/* about/all --env test/prod
后續(xù)

更多博客,查看 https://github.com/senntyou/blogs

作者:深予之 (@senntyou)

版權(quán)聲明:自由轉(zhuǎn)載-非商用-非衍生-保持署名(創(chuàng)意共享3.0許可證)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/99701.html

相關(guān)文章

  • 構(gòu)建Vue-cli通用項(xiàng)目目錄

    摘要:使用基于依賴追蹤的觀察并且使用異步隊(duì)列更新。為項(xiàng)目配置文件。為項(xiàng)目靜態(tài)資源目錄。其實(shí)個(gè)人感覺通用項(xiàng)目目錄可以很隨意的搭配,比如說之后清空目錄封裝通用組件,像是啊,滑動常用組件。 寫在前面的個(gè)人體會,大神們可以跳過 這段時(shí)間接手一個(gè)后臺管理項(xiàng)目,從最開始寫一點(diǎn)我自己的體會吧。首先Vue,Angular和React是當(dāng)今主流前端三大框架。Vue是一個(gè)用來構(gòu)建網(wǎng)頁的JS庫,相比較Angula...

    Winer 評論0 收藏0
  • 全棧開發(fā)自學(xué)路線

    摘要:前言這里筑夢師是一名正在努力學(xué)習(xí)的開發(fā)工程師目前致力于全棧方向的學(xué)習(xí)希望可以和大家一起交流技術(shù)共同進(jìn)步用簡書記錄下自己的學(xué)習(xí)歷程個(gè)人學(xué)習(xí)方法分享本文目錄更新說明目錄學(xué)習(xí)方法學(xué)習(xí)態(tài)度全棧開發(fā)學(xué)習(xí)路線很長知識拓展很長在這里收取很多人的建議以后決 前言 這里筑夢師,是一名正在努力學(xué)習(xí)的iOS開發(fā)工程師,目前致力于全棧方向的學(xué)習(xí),希望可以和大家一起交流技術(shù),共同進(jìn)步,用簡書記錄下自己的學(xué)習(xí)歷程...

    galaxy_robot 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<