webpack4從零開始構建(一)
webpack4+React16項目構建(二)
webpack4功能配置劃分細化(三)
webpack4引入Ant Design和Typescript(四)
webpack4代碼去重,簡化信息和構建優化(五)
webpack4配置Vue版腳手架(六)javascript
由於以前咱們已經花了五篇文章講解了怎麼從零配置一個React版的Webpack腳手架,接下來我打算之前面代碼爲基礎改爲Vue版.改變的第一步就是清除React全家桶和Typescript的痕跡.css
node_modules
和tsconfig.json
用不上了html
刪除不須要的依賴vue
{ "sideEffects": [ "*.scss", "*.css" ], "scripts": { "dev": "cross-env NODE_ENV=DEV webpack --config ./config/webpack.dev.js", "prod": "cross-env NODE_ENV=PROD webpack --config ./config/webpack.prod.js", "start": "cross-env NODE_ENV=SERVER webpack-dev-server --config ./config/webpack.server.js", "rnm": "rimraf node_modules" }, "dependencies": { }, "devDependencies": { "autoprefixer": "^9.4.10", "babel-core": "^6.26.3", "babel-loader": "7", "babel-preset-env": "^1.7.0", "babel-preset-react": "^6.24.1", "clean-webpack-plugin": "^2.0.0", "cross-env": "^5.2.0", "css-loader": "^2.1.1", "file-loader": "^3.0.1", "html-loader": "^0.5.5", "html-webpack-plugin": "^3.2.0", "image-webpack-loader": "^4.6.0", "mini-css-extract-plugin": "^0.5.0", "node-sass": "^4.11.0", "optimize-css-assets-webpack-plugin": "^5.0.1", "postcss-loader": "^3.0.0", "progress-bar-webpack-plugin": "^1.12.1", "rimraf": "^2.6.3", "sass-loader": "^7.1.0", "source-map-loader": "^0.2.4", "style-loader": "^0.23.1", "url-loader": "^1.1.2", "webpack": "^4.30.0", "webpack-bundle-analyzer": "^3.1.0", "webpack-cli": "^3.2.3", "webpack-dev-server": "^3.2.1", "webpack-merge": "^4.2.1", "webpack-parallel-uglify-plugin": "^1.1.0", "xml-loader": "^1.2.1" }, "name": "webpack_demo", "version": "1.0.0", "main": "index.tsx", "license": "MIT" }
只保留基本的處理規則java
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const { isProd, isServer } = require('./env') const cssMiniLoader = !isServer ? { loader: MiniCssExtractPlugin.loader, options: { // you can specify a publicPath here // by default it use publicPath in webpackOptions.output publicPath: process.env.NODE_ENV === "DEV" ? "./" : "../" } } : "style-loader"; // 使用<style>將css-loader內部樣式注入到咱們的HTML頁面, const postcssLoader = { loader: "postcss-loader", options: { config: { path: "./" // 寫到目錄便可,文件名強制要求是postcss.config.js } } }; const imgLoader = { loader: "url-loader", options: { name: "[name].[hash:5].[ext]", limit: 20 * 1024, // size <= 50kb outputPath: "img" } }; module.exports = [ { test: /\.s?css$/, // 匹配文件 use: [ cssMiniLoader, "css-loader", // 加載.css文件將其轉換爲JS模塊 postcssLoader, "sass-loader" // 加載 SASS / SCSS 文件並將其編譯爲 CSS ] }, { test: /\.(png|svg|jpe?g|gif)$/i, // 圖片處理 use: isProd ? [ imgLoader, { loader: "image-webpack-loader", options: { // Compress JPEG images mozjpeg: { progressive: true, quality: 65 }, // Compress PNG images optipng: { enabled: false }, // Compress PNG images pngquant: { quality: "65-90", speed: 4 }, // Compress GIF images gifsicle: { interlaced: false } } } ] : [ imgLoader ] }, { test: /\.(woff|woff2|eot|ttf|otf)$/, // 字體處理 use: ["file-loader"] }, { test: /\.xml$/, // 文件處理 use: ["xml-loader"] }, { test: /\.(html)$/, use: { loader: "html-loader" } } ];
保留目錄,除了圖片和樣式其餘文件都刪掉node
yarn add vue vue-router vuex yarn add --dev vue-loader vue-template-compiler
const path = require("path"); // 建立 import 或 require 的別名,來確保模塊引入變得更簡單 module.exports = { "@": path.resolve(__dirname, "../src/"), IMG: path.resolve(__dirname, "../src/img"), STYLE: path.resolve(__dirname, "../src/style"), JS: path.resolve(__dirname, "../src/js"), ROUTER: path.resolve(__dirname, "../src/router"), VUEX: path.resolve(__dirname, "../src/vuex"), PAGE: path.resolve(__dirname, "../src/page"), CMT: path.resolve(__dirname, "../src/component"), // 'vue$':'vue/dist/vue.js' };
最後一行你們可能有疑問,若是不添加的話會這麼輸出
咱們看node_omdules
裏vue倉庫的dist
目錄,裏面有不少的構建版本react
咱們從它的package.json文件看到webpack
"main": "dist/vue.runtime.common.js", "module": "dist/vue.runtime.esm.js", "unpkg": "dist/vue.js", "jsdelivr": "dist/vue.js",
從官網咱們找到這張圖es6
術語 | 描述 |
---|---|
完整版本(Full) | 包含編譯器(compiler) 和運行時(runtime) 的構建版本 |
編譯器(Compiler) | 負責將模板字符串編譯成 JavaScript render 函數的代碼 |
運行時(Runtime) | 負責建立 Vue 實例(creating Vue instances) 、渲染(rendering) 和修補虛擬 DOM(patching virtual DOM) 等的代碼。基本上,等同於完整版本減去編譯器 |
UMD | UMD 構建版本可以直接在瀏覽器中經過 <script> 標籤使用。jsDelivr CDN 提供的默認文件 https://cdn.jsdelivr.net/npm/vue,是運行時+編譯器(Runtime + Compiler)的 UMD 構建版本(vue.js) |
CommonJS | CommonJS 版本用於較早期的打包器(bundler)(例如 browserify 或 webpack 1 等)中。用於這些打包器的默認文件(pkg.main),是隻含有運行時(Runtime only)的 CommonJS 構建版本(vue.runtime.common.js) |
ES Module | ES 模塊版本構建用於現代打包器(例如 webpack 2 或 rollup 等)中。用於這些打包器的默認文件(pkg.module),是隻含有運行時(Runtime only)的 ES Module 構建版本(vue.runtime.esm.js) |
在使用 vue-loader
或 vueify
時,*.vue
文件中的模板會 在構建時(build time)預編譯(pre-compile)爲 JavaScript。最終生成的 bundle 中你再也不須要編譯器(compiler),所以能夠直接使用只含有運行時的構建版本(runtime-only)。web
因此咱們只要改一下初始化的方式就不必添加路徑使用完整版,具體方式下面src\index.js
和config/rules
文件配置會提到
更加具體的解釋能夠直接查看不一樣構建版本的解釋說明
<template> <div> <p>Page1</p> <img class="img1" src='../img/1.jpg' alt="" /> </div> </template> <script> export default {}; </script> <style lang="scss" scoped> </style>
<template> <div> <p>Page2</p> <div class="img2" /> </div> </template> <script> export default {}; </script> <style lang="scss" scoped> </style>
<template> <div id="app"> <router-link to="/view1">view1</router-link> <router-link to="/view2">view2</router-link> <router-view></router-view> </div> </template> <script> export default {}; </script>
import Vue from 'vue'; import Router from 'vue-router'; Vue.use(Router); let router = new Router({ routes: [ { // 首頁 path: '/view1', component: () => import('CMT/view1') }, { path: '/view2', component: () => import('CMT/view2') }, { path: '*', redirect: '/view1' } ] }); export default router;
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); export default new Vuex.Store({ state: { }, mutations: { } });
// page import 'STYLE/style.scss' import Vue from 'vue'; import router from 'ROUTER/index.js'; import store from 'VUEX/index.js'; import App from './App'; new Vue({ el: '#root', router, store, render: h => h(App) });
主要變化是插入了對ES語法編譯和Vue語法支持
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const { isProd, isServer } = require('./env') const cssMiniLoader = !isServer ? { loader: MiniCssExtractPlugin.loader, options: { // you can specify a publicPath here // by default it use publicPath in webpackOptions.output publicPath: process.env.NODE_ENV === "DEV" ? "./" : "../" } } : "style-loader"; // 使用<style>將css-loader內部樣式注入到咱們的HTML頁面, const postcssLoader = { loader: "postcss-loader", options: { config: { path: "./" // 寫到目錄便可,文件名強制要求是postcss.config.js } } }; const imgLoader = { loader: "url-loader", options: { name: "[name].[hash:5].[ext]", limit: 20 * 1024, // size <= 50kb outputPath: "img" } }; module.exports = [{ test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } }, { test: /\.vue$/, use: 'vue-loader' }, { test: /\.s?css$/, // 匹配文件 use: [ cssMiniLoader, "css-loader", // 加載.css文件將其轉換爲JS模塊 postcssLoader, "sass-loader" // 加載 SASS / SCSS 文件並將其編譯爲 CSS ] }, { test: /\.(png|svg|jpe?g|gif)$/i, // 圖片處理 use: isProd ? [ imgLoader, { loader: "image-webpack-loader", options: { // Compress JPEG images mozjpeg: { progressive: true, quality: 65 }, // Compress PNG images optipng: { enabled: false }, // Compress PNG images pngquant: { quality: "65-90", speed: 4 }, // Compress GIF images gifsicle: { interlaced: false } } } ] : [ imgLoader ] }, { test: /\.(woff|woff2|eot|ttf|otf)$/, // 字體處理 use: ["file-loader"] }, { test: /\.xml$/, // 文件處理 use: ["xml-loader"] }, { test: /\.(html)$/, use: { loader: "html-loader" } } ];
修改對應後綴擴展
extensions: ['.js', '.vue', '.json', 'scss', 'css']
改變入口地址
const path = require('path'); const isDev = process.env.NODE_ENV !== "DEV", isProd = process.env.NODE_ENV !== "PROD", isServer = process.env.NODE_ENV !== "SERVER", entry = "./src/index.js", outputName = "[name].bundle.js", outputPath = path.resolve(__dirname, "../dist"), publicPath = "", title = "test"; module.exports = { isDev, isProd, isServer, entry, outputName, outputPath, publicPath, title };
yarn add --dev babel-core babel-loader@7 babel-preset-env babel-preset-stage-2
以前只是粗略講過它的一些基本狀況,如今能夠單獨講講它裏面具體有什麼東西,除了以前說的
是做爲babel的核心,把 javascript 代碼分析成 AST (抽象語法樹, 是源代碼的抽象語法結構的樹狀表現形式),方便各個插件分析語法進行相應的處理
也是核心插件,容許使用Babel和webpack轉換JavaScript文件
初始的時候官方針對經常使用環境編寫了一些 preset,例如
preset | 做用 |
---|---|
babel-preset-es2015 | 能夠將es6的代碼編譯成es5 |
babel-preset-es2016 | 能夠將es7的代碼編譯爲es6 |
babel-preset-es2017 | 能夠將es8的代碼編譯爲es7 |
babel-preset-latest | 支持現有全部ECMAScript版本的新特性 |
完整模擬ES2015+環境,一次性引入全部模塊而且同項目代碼一塊兒編譯到生產環境。並且會污染全局變量,增長體積大概在200~300K左右
Babel 使用了很是小的 helpers 來實現諸如 _extend
等經常使用功能。默認狀況下,它將被添加到每一個經過 require 引用它的文件中。這種重複(操做)有時是沒必要要的,特別是當你的應用程序被拆分爲多個文件時。
全部的 helper 都會引用模塊 babel-runtime
,以免編譯輸出的重複問題。這個運行時會被編譯到你的構建版本當中。另一個目的就是爲你的代碼建立一個沙盒環境將內置插件起了別名
{ // 插件 "plugins": [ [ "transform-runtime", { "helpers": false, // 是否切換將內聯(inline)的 Babel helper(classCallCheck,extends 等)替換爲對 moduleName 的調用。 "polyfill": false, // 是否切換新的內置插件(Promise,Set,Map等)爲使用非全局污染的 polyfill。 "regenerator": true, // 是否切換 generator 函數爲不污染全局做用域的 regenerator 運行時。 "moduleName": "babel-runtime" // 當引入 helper 時,設置要使用的模塊的名稱/路徑。 } ] ], }
可是隨着歷史進程,愈來愈多的preset出現不便於開發配置,因而推出了babel-preset-env
基於你的實際瀏覽器及運行環境,自動的肯定babel插件及polyfills,轉譯ES2015及此版本以上的語言,默認配置狀況下和babel-preset-latest
一致
咱們直接配置兼容的版本狀況支持每一個瀏覽器最後兩個版本和safari大於等於7版本所需的polyfill代碼轉換
可是babel-preset-env
已提供方法能夠替代上面babel-plugin-transform-runtime
相似的做用了
// 預設 "presets": [ [ "env", { "modules": false, "targets": { "browsers": [ "last 2 versions", "safari >= 7" ] }, "useBuiltIns": "usage" // "usage" | "entry" | false, 默認爲 false } ] ],
由於沒有太深刻研究,具體有些差異不太清楚
TC39 將提案分爲如下幾個階段:
階段 | 描述 |
---|---|
Stage 0 - 設想(Strawman) | 只是一個想法,可能有 Babel插件 |
Stage 1 - 建議(Proposal) | 這是值得跟進的 |
Stage 2 - 草案(Draft) | 初始規範 |
Stage 3 - 候選(Candidate) | 完成規範並在瀏覽器上初步實現 |
Stage 4 - 完成(Finished) | 將添加到下一個年度版本發佈中 |
由於babel-preset-env
只支持最新推出版本的JavaScript語法(state-4),因此若是想要體驗部分還爲完成階段的新語法能夠配置對應的插件轉換,通常主流推薦使用2.
// 預設 "presets": [ [ "env", { "modules": false, "targets": { "browsers": [ "last 2 versions", "safari >= 7" ] }, "useBuiltIns": "usage" // "usage" | "entry" | false, 默認爲 false } ] "stage-2" ],
還有部分暫時沒用上的東西
{ // 預設 "presets": [ [ "env", { "modules": false, "targets": { "browsers": [ "last 2 versions", "safari >= 7" ] }, "useBuiltIns": "usage" // "usage" | "entry" | false, 默認爲 false } ], "stage-2" ], // 插件 "plugins": [], /* 設置特定的配置選項 env 選項的值將從 process.env.BABEL_ENV 獲取,若是沒有的話,則獲取 process.env.NODE_ENV 的值,它也沒法獲取時會設置爲 "development" */ "env": { "development": {}, "production": {} } }
若是以當前配置運行命令
yarn start
終端會輸出錯誤如圖
因此咱們須要根據錯誤提示引入Vue-loader
插件
const VueLoaderPlugin = require('vue-loader/lib/plugin'); ------------------省略----------------------- plugins: [ new VueLoaderPlugin(), ],
再次運行便可正常.