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(), ],
再次运行便可正常.