初始化打包公共npm包,加快打包速度javascript
npm run dll 或者 yarn dll
開發環境css
npm run dev 或者 yarn dev
生產環境打包html
npm run build 或者 yarn build
首先附上官方的文檔html5
github地址java
https://github.com/xiaopingzh...
會不定時更新,若是以爲有幫助到你,給個Star當作鼓勵可好。node
. ├── README.md ├── build │ ├── webpack.dev.conf.js │ ├── webpack.dll.conf.js │ └── webpack.prod.conf.js ├── dist ├── dll ├── manifest.json ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── components │ │ ├── Bread │ │ │ └── Bread.js │ │ └── SiderBar │ │ └── SiderBar.js │ ├── index.js │ ├── layouts │ │ └── BasicLayout.js │ ├── pages │ │ ├── Counter │ │ │ └── Counter.js │ │ └── Home │ │ └── Home.js │ ├── redux │ │ ├── actions │ │ │ └── counter.js │ │ ├── reducer.js │ │ ├── reducers │ │ │ └── counter.js │ │ └── store.js │ ├── request │ │ └── request.js │ ├── router │ │ └── Router.js │ └── util │ └── loadable.js └── yarn.lock
webpack
,再安裝webpack-cli
>npm init This utility will walk you through creating a package.json file. It only covers the most common items, and tries to guess sensible defaults. See `npm help json` for definitive documentation on these fields and exactly what they do. Use `npm install <pkg>` afterwards to install a package and save it as a dependency in the package.json file. Press ^C at any time to quit. package name: (webpack4) version: (1.0.0) description: entry point: (index.js) test command: git repository: keywords: author: license: (ISC) About to write to /Users/xiaopingzhang/UCloud/webpack4/package.json: { "name": "webpack4", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" } Is this OK? (yes) yes
初始化以後按照提示一步步往下就能夠了,能夠輸入該項目的描述等等信息。一開始也沒有關係,後面也還能夠更改。react
下一步 本地安裝webpack
,再安裝webpack-cli
webpack
npm install webpack webpack-cli --save-dev
==--save-dev
是你開發時候依賴的東西,--save
是你發佈以後還依賴的東西。==ios
>npm install webpack webpack-cli --save-dev > fsevents@1.2.7 install /Users/xiaopingzhang/UCloud/webpack4/node_modules/fsevents > node install node-pre-gyp WARN Using needle for node-pre-gyp https download [fsevents] Success: "/Users/xiaopingzhang/UCloud/webpack4/node_modules/fsevents/lib/binding/Release/node-v57-darwin-x64/fse.node" is installed via remote > webpack-cli@3.2.1 postinstall /Users/xiaopingzhang/UCloud/webpack4/node_modules/webpack-cli > lightercollective *** Thank you for using webpack-cli! *** Please consider donating to our open collective to help us maintain this package. https://opencollective.com/webpack/donate *** npm WARN webpack4@1.0.0 No description npm WARN webpack4@1.0.0 No repository field. + webpack-cli@3.2.1 + webpack@4.29.0 added 458 packages from 239 contributors and audited 5208 packages in 18.624s found 0 vulnerabilities
安裝好以後,也會顯示安裝的哪一個版本,通常安裝沒有啥問題。實在安裝不成功,試一下全局安裝。git
2.新建src
文件夾,入口的js
文件和html
文件。
. ├── index.html ├── package.json └── src └── index.js
index.js文件
const component = () => { let element = document.createElement("div"); element.innerHTML = "webpackworks"; return element; }; document.body.appendChild(component());
index.html
<!DOCTYPE html> <html> <head> <title>Start</title> </head> <body> <script src="./dist/main.js"></script> </body> </html>
3.學會使用webpack編譯文件
輸入 npx webpack
>npx webpack Hash: 9ad2a368debc9967c1f4 Version: webpack 4.29.0 Time: 269ms Built at: 2019-01-27 21:15:22 Asset Size Chunks Chunk Names main.js 1.01 KiB 0 [emitted] main Entrypoint main = main.js [0] ./src/index.js 218 bytes {0} [built] WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
再用瀏覽器打開index.html
,查看網頁是否正常的顯示了。
webpack 把入口文件 index.js
通過處理以後,生成 main.js
通過第一部分的嘗試,已經初步瞭解webpack
的做用,這一部分經過配置文件進行相應的一些設置。
Babel 把用最新標準編寫的 JavaScript 代碼向下編譯成能夠在今天隨處可用的版本。 這一過程叫作「源碼到源碼」編譯, 也被稱爲轉換編譯。
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-0
新建babel配置文件.babelrc
{ "presets": [ "es2015", "react", "stage-0" ], "plugins": [] } //babel-core 調用Babel的API進行轉碼 //babel-loader //babel-preset-es2015 用於解析 ES6 //babel-preset-react 用於解析 JSX //babel-preset-stage-0 用於解析 ES7 提案
webpack.base.conf.js webpack.dev.conf.js webpack.prod.conf.js
分別是公共配置,開發配置,生產配置。
目前目錄結構爲
. ├── build │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ └── webpack.prod.conf.js ├── dist │ └── main.js ├── index.html ├── package.json └── src └── index.js
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-0
在 src 目錄下新建.babelrc
{ "presets": [ [ "env", { "targets": { "browsers": [">1%", "last 3 versions"] } } ], "stage-2", "latest", "react" ], "plugins": [ "syntax-dynamic-import", "transform-class-properties", <!--[--> <!-- "import",--> <!-- {--> <!-- "libraryName": "antd",--> <!-- "libraryDirectory": "es",--> <!-- "style": true--> // "style": "css" //主題設置 <!-- }--> <!--]--> 不用antd 能夠去掉 ] }
文件新增
{ test: /\.(js|jsx)$/, exclude: /(node_modules|bower_components)/, //排除 include: [ path.resolve(__dirname, '../src') ], //包括 use: { loader: 'babel-loader' } },
npm install --save-dev style-loader css-loader
在配置文件裏添加
{ test: /\.css$/, use: ["style-loader", "css-loader"] }
npm install --save-dev url-loader file-loader
在配置文件裏添加
{ test: /\.(png|jpg|gif)$/, use: [ { loader: "url-loader", options: { limit: 8192 } } ] }
options limit:8192
意思是,小於等於8K的圖片會被轉成base64編碼,直接插入HTML中,減小HTTP請求。
在這個踩了一個坑,記得安裝 less
npm install --save-dev less-loader less
更改antd 默認主題設置須要,不用的話應該把相應的設置忽略便可。
{ test: /\.less$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' // translates CSS into CommonJS }, { loader: 'less-loader', // compiles Less to CSS options: { modifyVars: { 'font-size-base': '12px', 'primary-color': '#0EA679' }, javascriptEnabled: true } } ] }
那麼,像字體這樣的其餘資源如何處理呢?file-loader 和 url-loader 能夠接收並加載任何文件,而後將其輸出到構建目錄。這就是說,咱們能夠將它們用於任何類型的文件,包括字體。更新 webpack.config.js 來處理字體文件:
{ test: /\.(woff|woff2|eot|ttf|otf)$/, use: ["file-loader"] }
HtmlWebpackPlugin做用是生成一個HTML模板。
HtmlWebpackPlugin簡化了HTML文件的建立,以便爲你的webpack包提供服務。這對於在文件名中包含每次會隨着編譯而發生變化哈希的 webpack bundle 尤爲有用。
你可讓插件爲你生成一個HTML文件,使用lodash模板提供你本身的模板,或使用你本身的loader
首先須要安裝插件:
npm install --save-dev html-webpack-plugin
在生產配置文件裏添加
plugins: [ new HtmlWebpackPlugin({ template: 'public/index.html', title: 'title', // 更改HTML的title的內容 favicon: 'public/favicon.ico', minify: { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true, }, }),
在每次構建前清理 /dist 文件夾.
npm install clean-webpack-plugin --save-dev
new CleanWebpackPlugin(['../dist'])
https://webpack.docschina.org...
模塊熱替換(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它容許在運行時更新各類模塊,而無需進行徹底刷新。
有兩種方式
"dev": "webpack --config build/webpack.dev.config.js --color --progress --hot"
import React from 'react'; import ReactDom from 'react-dom'; **if (module.hot) { module.hot.accept(); }** //增長
const webpack = require('webpack'); devServer: { hot: true } plugins:[ new webpack.HotModuleReplacementPlugin() ]
https://www.redux.org.cn/
官方文檔先給上,一開始學的時候也覺得這個比較難,開始寫就不會了。
網上看看例子,本身在coding一下就差很少了。
這邊用到了一箇中間件 redux-thunk
npm install --save redux-thunk
附上寫的代碼
註釋的部分爲生產環境使用。
爲了方便debug代碼,在控制檯打印readux日誌。
// import { createStore, applyMiddleware } from 'redux'; // import thunk from 'redux-thunk'; // import rootReducer from './reducer'; // const createStoreWithMiddleware = applyMiddleware(thunk)(createStore); // const store = createStoreWithMiddleware(rootReducer); // export default store; // 打印操做日誌,方便調試,生產環境能夠去掉,用上面註釋的配置。 import thunk from "redux-thunk"; // redux 做者開發的異步處理方案 能夠在action 裏傳入 dispatch getState import { createLogger } from "redux-logger"; // 利用redux-logger打印日誌 import { createStore, applyMiddleware } from "redux"; // 引入redux createStore、中間件及compose import { composeWithDevTools } from "redux-devtools-extension"; // devToolsEnhancer, import reducer from "./reducer"; // 引入reducers集合 // 調用日誌打印方法 collapsed是讓action摺疊,看着舒服點 const loggerMiddleware = createLogger({ collapsed: true }); // 建立一箇中間件集合 const middleware = [thunk, loggerMiddleware]; // 建立store const store = createStore( reducer, composeWithDevTools(applyMiddleware(...middleware)) ); export default store;
export const INCREMENT = 'counter/INCREMENT'; export const DECREMENT = 'counter/DECREMENT'; export const RESET = 'counter/RESET'; export function increment() { return { type: INCREMENT }; } export function decrement() { return { type: DECREMENT }; } export function reset() { return { type: RESET }; }
import { INCREMENT, DECREMENT, RESET } from '../actions/counter'; const initState = { count: 0, }; export default function reducer(state = initState, action) { switch (action.type) { case INCREMENT: return { count: state.count + 1, }; case DECREMENT: return { count: state.count - 1, }; case RESET: return { count: 0 }; default: return state; } }
import { combineReducers } from "redux"; import counter from "./reducers/counter"; export default combineReducers({ counter });
https://github.com/jamiebuild...
官方文檔先附上
// 加載頁面 import Loadable from 'react-loadable'; import React, { Component } from 'react'; import { Spin, Icon } from 'antd'; const antIcon = <Icon type="loading" style={{ fontSize: 24 }} spin />; const antLong = ( <Icon type="loading" style={{ fontSize: 24, color: 'red' }} spin /> ); const antError = ( <Icon type="loading" style={{ fontSize: 24, color: 'red' }} spin /> ); export const Loading = props => { if (props.error) { return ( <Spin size="large" tip="加載錯誤 。。。" indicator={antError} style={{ position: 'absolute', color: 'red', top: '40%', left: '50%' }} /> ); } else if (props.timedOut) { return ( <Spin size="large" tip="加載超時 。。。" indicator={antLong} style={{ position: 'absolute', color: 'red', top: '40%', left: '50%' }} /> ); } else if (props.pastDelay) { return ( <Spin size="large" tip="Loading 。。。" indicator={antError} style={{ position: 'absolute', color: 'red', top: '40%', left: '50%' }} /> ); } else { return null; } }; export const importPath = ({ loader }) => { return Loadable({ loader, loading: Loading, delay: 200, timeout: 10000 }); };
在須要用到的地方引入這個文件就ok了。只是簡單的寫了一個例子,後續再完善吧。axios使用起來很簡潔。
import axios from "axios"; import { message } from "antd"; import NProgress from "nprogress"; import "nprogress/nprogress.css"; // 攔截全部有請求與回覆 // Add a request interceptor axios.interceptors.request.use( config => { NProgress.start(); return config; }, error => { message.error("請求錯誤,請重試"); return Promise.reject(error); } ); // Add a response interceptor axios.interceptors.response.use( response => { // NProgress.done(); // if (response.data.RetCode === 101) { // message.error(response.data.Message); // return response; // } // if (response.data.RetCode === 100) { // message.error(response.data.Message); // return response; // } return response; }, error => { message.error("請求錯誤,請重試"); NProgress.done(); return Promise.reject(error); } ); export default request;
plugins: [ // 處理html new HtmlWebpackPlugin({ template: 'public/index.html', path: '../public/index.html', inject: 'body', title: '管理平臺', favicon: 'public/favicon.ico', filename: 'index.html', hash: true, minify: { html5: true, removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true } }), new CleanWebpackPlugin(['../dist'], { allowExternal: true }), new BundleAnalyzerPlugin(), new MiniCssExtractPlugin({ chunkFilename: '[chunkhash].css' }), new webpack.HashedModuleIdsPlugin(), new webpack.DllReferencePlugin({ context: __dirname, manifest: require('../dll/manifest.json') }), new CopyWebpackPlugin([ { from: 'dll/Dll.js', to: DIST_PATH } ]) ]
const HtmlWebpackPlugin = require('html-webpack-plugin'); new HtmlWebpackPlugin({ template: 'public/index.html', path: '../public/index.html', inject: 'body', title: '管理平臺', favicon: 'public/favicon.ico', filename: 'index.html', hash: true, minify: { html5: true, removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true } }),
const CopyWebpackPlugin = require('copy-webpack-plugin'); new CopyWebpackPlugin([ { from: 'dll/Dll.js', to: DIST_PATH } ])
const CleanWebpackPlugin = require('clean-webpack-plugin'); new CleanWebpackPlugin(['../dist'], { allowExternal: true })
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer') .BundleAnalyzerPlugin; new BundleAnalyzerPlugin(),
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); new MiniCssExtractPlugin({ chunkFilename: '[chunkhash].css' })
const path = require('path'); const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const DIST_PATH = path.resolve(__dirname, '../dist'); //生產目錄 const APP_PATH = path.resolve(__dirname, '../src'); //源文件目錄 module.exports = { mode: 'development', entry: { index: './src/index.js' }, output: { path: DIST_PATH, //出口路徑 filename: 'index.js', chunkFilename: 'js/[name].[chunkhash].js', //按需加載名稱 // publicPath: "./" }, // 源錯誤檢查 devtool: 'inline-source-map', //模塊配置 module: { rules: [ { test: /\.(js|jsx)$/, exclude: /(node_modules|bower_components)/, //排除 include: [ path.resolve(__dirname, '../src'), path.resolve(__dirname, '../node_modules/antd/') ], //包括 use: { loader: 'babel-loader' } }, { test: /\.css$/, use: ['style-loader', 'css-loader'] }, { test: /\.(png|jpg|gif)$/, use: [ { loader: 'url-loader', options: { limit: 8192 } } ] }, { test: /\.(woff|woff2|eot|ttf|otf)$/, use: ['file-loader'] }, //更改antd主題設置 { test: /\.less$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' // translates CSS into CommonJS }, { loader: 'less-loader', // compiles Less to CSS options: { modifyVars: { 'font-size-base': '12px', 'primary-color': '#0EA679' }, javascriptEnabled: true } } ] } ] }, //插件 plugins: [ new HtmlWebpackPlugin({ template: 'public/index.html', path: '../public/index.html', inject: 'body', favicon: 'public/favicon.ico', title: '管理平臺', overlay: true, minify: { html5: false }, hash: true }), // 熱更新 new webpack.HotModuleReplacementPlugin(), new webpack.HashedModuleIdsPlugin(), new webpack.DllReferencePlugin({ context: __dirname, manifest: require('../dll/manifest.json') }), new CopyWebpackPlugin([ { from: 'dll/Dll.js', to: DIST_PATH } ]) ], // 熱更新 devServer: { port: '3300', contentBase: DIST_PATH, historyApiFallback: true, hot: true, // 開啓 https: false, compress: false, noInfo: true, open: true, proxy: { // '/': { // target: '', // changeOrigin: true, // secure: false, // }, } } };
const path = require('path'); const webpack = require('webpack'); const CleanWebpackPlugin = require('clean-webpack-plugin'); const vendors = [ 'antd', 'axios', 'nprogress', 'react', 'react-dom', 'react-loadable', 'react-redux', 'react-router', 'react-router-dom', 'redux' ]; module.exports = { entry: { vendor: vendors }, output: { path: path.resolve(__dirname, '../dll'), filename: 'Dll.js', library: '[name]_[hash]' }, plugins: [ new webpack.DllPlugin({ path: path.resolve(__dirname, '../dll', 'manifest.json'), name: '[name]_[hash]', context: __dirname }), new CleanWebpackPlugin(['../dll'], { allowExternal: true }) ] };
const path = require('path'); const webpack = require('webpack'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const CleanWebpackPlugin = require('clean-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const BundleAnalyzerPlugin = require('webpack-bundle-analyzer') .BundleAnalyzerPlugin; const DIST_PATH = path.resolve(__dirname, '../dist'); //生產目錄 module.exports = { mode: 'production', entry: { index: './src/index.js' }, output: { path: DIST_PATH, //出口路徑 filename: 'index.js', chunkFilename: '[name]_[hash].js', //按需加載名稱 // publicPath: './' }, // 源錯誤檢查 devtool: 'source-map', //模塊配置 module: { rules: [ { test: /\.(js|jsx)$/, exclude: /(node_modules|bower_components)/, //排除 include: [ path.resolve(__dirname, '../src'), path.resolve(__dirname, '../node_modules/antd/') ], //包括 use: { loader: 'babel-loader' } }, { test: /\.css$/, use: ['style-loader', 'css-loader'] }, { test: /\.(png|jpg|gif)$/, use: [ { loader: 'url-loader', options: { limit: 8192 } } ] }, //更改antd主題設置 { test: /\.less$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' // translates CSS into CommonJS }, { loader: 'less-loader', // compiles Less to CSS options: { minimize: true, modifyVars: { 'font-size-base': '12px', 'primary-color': '#0EA679' }, javascriptEnabled: true } } ] }, { test: /\.(woff|woff2|eot|ttf|otf)$/, use: ['file-loader'] } ] }, //插件 plugins: [ // 處理html new HtmlWebpackPlugin({ template: 'public/index.html', path: '../public/index.html', inject: 'body', title: '管理平臺', favicon: 'public/favicon.ico', filename: 'index.html', hash: true, minify: { html5: true, removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true } }), new CleanWebpackPlugin(['../dist'], { allowExternal: true }), new BundleAnalyzerPlugin(), new MiniCssExtractPlugin({ chunkFilename: '[chunkhash].css' }), new webpack.HashedModuleIdsPlugin(), new webpack.DllReferencePlugin({ context: __dirname, manifest: require('../dll/manifest.json') }), new CopyWebpackPlugin([ { from: 'dll/Dll.js', to: DIST_PATH } ]) ] // 熱更新 };
ERROR in Path must be a string. Received undefined Child html-webpack-plugin for "index.html": 1 asset Entrypoint undefined = index.html
這個錯誤不影響打包結果,應該是版本問題致使。
https://github.com/jantimon/h...
寫完才發現有些忘記記錄了,會保持更新。
學習的過程當中也學習參考了其餘優秀的博客和github,以及文檔。
https://github.com/brickspert...https://github.com/NewPrototy...
https://github.com/axios/axios