First commit
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.vscode
|
||||||
|
node_modules/
|
||||||
|
package-lock.json
|
||||||
|
dist/
|
||||||
|
.DS_Store
|
||||||
42
package.json
Normal file
42
package.json
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "portfolio",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node ./server.js",
|
||||||
|
"build": "NODE_ENV=production webpack --config webpack.prod.js",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.17.5",
|
||||||
|
"@babel/preset-env": "^7.16.11",
|
||||||
|
"@babel/preset-react": "^7.16.7",
|
||||||
|
"babel-loader": "^8.2.3",
|
||||||
|
"clean-webpack-plugin": "^4.0.0",
|
||||||
|
"css-minimizer-webpack-plugin": "^3.4.1",
|
||||||
|
"express": "^4.17.3",
|
||||||
|
"html-critical-webpack-plugin": "^2.1.0",
|
||||||
|
"html-loader": "^3.1.0",
|
||||||
|
"html-webpack-plugin": "^5.5.0",
|
||||||
|
"image-minimizer-webpack-plugin": "^3.2.3",
|
||||||
|
"mini-css-extract-plugin": "^2.6.0",
|
||||||
|
"sass": "^1.49.9",
|
||||||
|
"sass-loader": "^12.6.0",
|
||||||
|
"style-loader": "^3.3.1",
|
||||||
|
"webpack": "^5.70.0",
|
||||||
|
"webpack-cli": "^4.9.2",
|
||||||
|
"webpack-dev-middleware": "^5.3.1",
|
||||||
|
"webpack-hot-middleware": "^2.25.1",
|
||||||
|
"webpack-merge": "^5.8.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@react-three/fiber": "^7.0.26",
|
||||||
|
"react": "^17.0.2",
|
||||||
|
"react-dom": "^17.0.2",
|
||||||
|
"three": "^0.138.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
32
server.js
Normal file
32
server.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
const path = require( 'path' );
|
||||||
|
const express = require( 'express' );
|
||||||
|
const webpack = require( 'webpack' );
|
||||||
|
const webpackDevMiddleware = require( 'webpack-dev-middleware' );
|
||||||
|
const webpackHotMiddleware = require( 'webpack-hot-middleware' );
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const config = require('./webpack.dev.js');
|
||||||
|
const compiler = webpack(config);
|
||||||
|
|
||||||
|
// Tell express to use the webpack-dev-middleware and use the webpack.config.js
|
||||||
|
// configuration file as a base.
|
||||||
|
app.use(
|
||||||
|
webpackDevMiddleware(compiler, {
|
||||||
|
publicPath: config.output.publicPath,
|
||||||
|
writeToDisk: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
app.use( webpackHotMiddleware(compiler, {
|
||||||
|
noInfo: true,
|
||||||
|
quiet: true
|
||||||
|
}) );
|
||||||
|
|
||||||
|
app.get( '/*', function(req, res) {
|
||||||
|
res.sendFile( 'index.html', {root: path.join( __dirname, './dist/')});
|
||||||
|
} );
|
||||||
|
|
||||||
|
// Serve the files on port 3000.
|
||||||
|
app.listen(3000, function () {
|
||||||
|
console.log('Example app listening on port 3000!\n');
|
||||||
|
});
|
||||||
39
src/components/App.jsx
Normal file
39
src/components/App.jsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import '../styles/styles.scss';
|
||||||
|
import { useRef, useState } from 'react';
|
||||||
|
import { Canvas, useFrame } from '@react-three/fiber';
|
||||||
|
|
||||||
|
const Box = (props) => {
|
||||||
|
// This reference gives us direct access to the THREE.Mesh object
|
||||||
|
const ref = useRef()
|
||||||
|
// Hold state for hovered and clicked events
|
||||||
|
const [hovered, hover] = useState(false)
|
||||||
|
const [clicked, click] = useState(false)
|
||||||
|
// Subscribe this component to the render-loop, rotate the mesh every frame
|
||||||
|
useFrame((state, delta) => (ref.current.rotation.x += 0.01))
|
||||||
|
// Return the view, these are regular Threejs elements expressed in JSX
|
||||||
|
return (
|
||||||
|
<mesh
|
||||||
|
{...props}
|
||||||
|
ref={ref}
|
||||||
|
scale={clicked ? 1.5 : 1}
|
||||||
|
onClick={(event) => click(!clicked)}
|
||||||
|
onPointerOver={(event) => hover(true)}
|
||||||
|
onPointerOut={(event) => hover(false)}>
|
||||||
|
<boxGeometry args={[1, 1, 1]} />
|
||||||
|
<meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
|
||||||
|
</mesh>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const App = () => {
|
||||||
|
return (
|
||||||
|
<Canvas>
|
||||||
|
<ambientLight />
|
||||||
|
<pointLight position={[10, 10, 10]} />
|
||||||
|
<Box position={[-1.2, 0, 0]} />
|
||||||
|
<Box position={[1.2, 0, 0]} />
|
||||||
|
</Canvas>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
||||||
10
src/scripts/app.js
Normal file
10
src/scripts/app.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { render } from 'react-dom';
|
||||||
|
import App from '../components/App';
|
||||||
|
|
||||||
|
render(
|
||||||
|
<App />,
|
||||||
|
document.getElementById("root") );
|
||||||
|
|
||||||
|
if (module['hot']) {
|
||||||
|
module['hot'].accept();
|
||||||
|
}
|
||||||
3
src/styles/styles.scss
Normal file
3
src/styles/styles.scss
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
main {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
12
src/views/index.html
Normal file
12
src/views/index.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Document</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main id="root"></main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
125
webpack.common.js
Normal file
125
webpack.common.js
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const MiniCSSExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
// let htmlPageNames = [];
|
||||||
|
// let multipleHtmlPlugins = htmlPageNames.map(name => {
|
||||||
|
// return new HtmlWebpackPlugin({
|
||||||
|
// template: `./src/views/${name}.html`, // relative path to the HTML files
|
||||||
|
// filename: `${name}.html`, // output HTML files
|
||||||
|
// chunks: [`${name}`] // respective JS files
|
||||||
|
// })
|
||||||
|
// });
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.jsx'],
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
// HTML
|
||||||
|
{
|
||||||
|
test: /\.html$/,
|
||||||
|
use: {
|
||||||
|
loader: 'html-loader',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// JS
|
||||||
|
{
|
||||||
|
test: /\.jsx?$/i,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
include: path.resolve(__dirname, 'src'),
|
||||||
|
use: {
|
||||||
|
loader: 'babel-loader',
|
||||||
|
options: {
|
||||||
|
presets: [
|
||||||
|
'@babel/preset-env',
|
||||||
|
['@babel/preset-react', { runtime: 'automatic' }],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// CSS
|
||||||
|
{
|
||||||
|
test: /\.s[ac]ss$/i,
|
||||||
|
use: [
|
||||||
|
MiniCSSExtractPlugin.loader,
|
||||||
|
'css-loader',
|
||||||
|
'postcss-loader',
|
||||||
|
'resolve-url-loader',
|
||||||
|
'sass-loader',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// Images
|
||||||
|
|
||||||
|
{
|
||||||
|
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
||||||
|
type: 'asset',
|
||||||
|
},
|
||||||
|
|
||||||
|
// {
|
||||||
|
// test: /\.(jpg|png|gif|svg)$/,
|
||||||
|
// use: {
|
||||||
|
// loader: 'url-loader'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
|
||||||
|
// {
|
||||||
|
// test: /\.(jpg|png|gif|svg)$/,
|
||||||
|
// use:
|
||||||
|
// [
|
||||||
|
// {
|
||||||
|
// loader: 'file-loader',
|
||||||
|
// options:
|
||||||
|
// {
|
||||||
|
// outputPath: './assets/images/'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// },
|
||||||
|
|
||||||
|
// Fonts
|
||||||
|
|
||||||
|
{
|
||||||
|
test: /\.(woff|woff2|eot|ttf|otf)$/i,
|
||||||
|
type: 'asset/resource',
|
||||||
|
},
|
||||||
|
|
||||||
|
// {
|
||||||
|
// test: /\.(ttf|eot|woff|woff2)$/,
|
||||||
|
// use:
|
||||||
|
// [
|
||||||
|
// {
|
||||||
|
// loader: 'file-loader',
|
||||||
|
// options:
|
||||||
|
// {
|
||||||
|
// outputPath: './assets/fonts/'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: path.resolve(__dirname, './src/views/index.html'),
|
||||||
|
inject: 'body',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
optimization: {
|
||||||
|
moduleIds: 'deterministic',
|
||||||
|
runtimeChunk: 'single',
|
||||||
|
splitChunks: {
|
||||||
|
cacheGroups: {
|
||||||
|
vendor: {
|
||||||
|
test: /[\\/]node_modules[\\/]/,
|
||||||
|
name: 'vendors',
|
||||||
|
chunks: 'all',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
60
webpack.dev.js
Normal file
60
webpack.dev.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
const { merge } = require('webpack-merge');
|
||||||
|
const webpack = require( 'webpack' );
|
||||||
|
const commonConfiguration = require('./webpack.common.js');
|
||||||
|
const MiniCSSExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const hotMiddlewareScript =
|
||||||
|
'webpack-hot-middleware/client?reload=true';
|
||||||
|
|
||||||
|
module.exports = merge(commonConfiguration, {
|
||||||
|
mode: 'development',
|
||||||
|
entry: {
|
||||||
|
portfolio: [hotMiddlewareScript, './src/scripts/app.js'],
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: 'js/[name].[contenthash].js',
|
||||||
|
path: path.resolve(__dirname, './dist'),
|
||||||
|
publicPath: '/',
|
||||||
|
clean: true,
|
||||||
|
// hotUpdateChunkFilename: 'hot/hot-update.js',
|
||||||
|
// hotUpdateMainFilename: 'hot/hot-update.json'
|
||||||
|
},
|
||||||
|
devtool: 'source-map',
|
||||||
|
plugins: [
|
||||||
|
new webpack.HotModuleReplacementPlugin(),
|
||||||
|
new MiniCSSExtractPlugin({
|
||||||
|
filename: 'css/[name].[contenthash].css',
|
||||||
|
}),
|
||||||
|
// new ImageMinimizerPlugin({
|
||||||
|
// minimizerOptions: {
|
||||||
|
// // Lossless optimization with custom option
|
||||||
|
// // Feel free to experiment with options for better result for you
|
||||||
|
// plugins: [
|
||||||
|
// ['gifsicle', { interlaced: true }],
|
||||||
|
// ['jpegtran', { progressive: true }],
|
||||||
|
// ['optipng', { optimizationLevel: 5 }],
|
||||||
|
// // Svgo configuration here https://github.com/svg/svgo#configuration
|
||||||
|
// [
|
||||||
|
// 'svgo',
|
||||||
|
// {
|
||||||
|
// plugins: [
|
||||||
|
// {
|
||||||
|
// name: 'removeViewBox',
|
||||||
|
// active: false,
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'addAttributesToSVGElement',
|
||||||
|
// params: {
|
||||||
|
// attributes: [{ xmlns: 'http://www.w3.org/2000/svg' }],
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// }),
|
||||||
|
]
|
||||||
|
});
|
||||||
78
webpack.prod.js
Normal file
78
webpack.prod.js
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
const { merge } = require('webpack-merge');
|
||||||
|
const commonConfiguration = require('./webpack.common.js');
|
||||||
|
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||||
|
const path = require('path');
|
||||||
|
const MiniCSSExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
const HtmlCriticalPlugin = require('html-critical-webpack-plugin');
|
||||||
|
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
||||||
|
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
|
||||||
|
|
||||||
|
module.exports = merge(commonConfiguration, {
|
||||||
|
mode: 'production',
|
||||||
|
entry: {
|
||||||
|
popshop: path.resolve(__dirname, './src/scripts/app.js'),
|
||||||
|
},
|
||||||
|
devtool: 'source-map',
|
||||||
|
output: {
|
||||||
|
filename: 'js/[name].[contenthash].js',
|
||||||
|
path: path.resolve(__dirname, './dist'),
|
||||||
|
clean: true,
|
||||||
|
assetModuleFilename: 'assets/images/[name][ext][query]',
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new CleanWebpackPlugin(),
|
||||||
|
new MiniCSSExtractPlugin({
|
||||||
|
filename: 'css/[name].[contenthash].css',
|
||||||
|
}),
|
||||||
|
// new ImageMinimizerPlugin({
|
||||||
|
// minimizerOptions: {
|
||||||
|
// // Lossless optimization with custom option
|
||||||
|
// // Feel free to experiment with options for better result for you
|
||||||
|
// plugins: [
|
||||||
|
// ['gifsicle', { interlaced: true }],
|
||||||
|
// ['jpegtran', { progressive: true }],
|
||||||
|
// ['optipng', { optimizationLevel: 5 }],
|
||||||
|
// // Svgo configuration here https://github.com/svg/svgo#configuration
|
||||||
|
// [
|
||||||
|
// 'svgo',
|
||||||
|
// {
|
||||||
|
// plugins: [
|
||||||
|
// {
|
||||||
|
// name: 'removeViewBox',
|
||||||
|
// active: false,
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'addAttributesToSVGElement',
|
||||||
|
// params: {
|
||||||
|
// attributes: [{ xmlns: 'http://www.w3.org/2000/svg' }],
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// }),
|
||||||
|
new HtmlCriticalPlugin({
|
||||||
|
base: path.join(path.resolve(__dirname), 'dist/'),
|
||||||
|
src: 'index.html',
|
||||||
|
dest: 'index.html',
|
||||||
|
inline: true,
|
||||||
|
minify: true,
|
||||||
|
extract: true,
|
||||||
|
width: 375,
|
||||||
|
height: 565,
|
||||||
|
penthouse: {
|
||||||
|
blockJSRequests: false,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
optimization: {
|
||||||
|
minimize: true,
|
||||||
|
minimizer: [
|
||||||
|
new CssMinimizerPlugin({
|
||||||
|
parallel: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user