Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Mar 30, 2022. It is now read-only.

Example Github Page PWA with NextJs, Redux-toolkit and Sql.js

License

NotificationsYou must be signed in to change notification settings

Project-Setup/github_sql_pwa

Repository files navigation

Highlight

  • Multi-pageReactProgressive Web App
  • Installable foroffline use through Chrome on desktop ormobile
  • Can be statically hosted onGithub Page for free (or as a regular web app hosted on a custom server)
  • Dynamically loadedRedux reducers forcode splitting
  • On browserSQL database
  • Prefetch security sensitive content at build time
  • All inTypescript/Javascript withCSS-in-JS
  • Easy testing withJest andEnzyme
  • Eslint helps practice standard coding styles

Versions

  • NextJs v9.4.2
  • Redux-Toolkit v1.3.6
  • Emotion v10
  • Sql.js v1.2.2
  • Typeorm v0.2.24
  • Typescript v3.9.2

Other Project Setup

Usage of this example setup

  1. setup node env
    nvm usenpm install
  2. remove unwanted files inpublic/,src/
  3. add.env and other .env files
  4. preview dev progress onhttp://localhost:3000/
    npm run dev
  5. export todocs/ for Github Page deploy
    npm runexport
  6. readSetup for notes

Setup

  1. install nvm in the os
  2. nvm install nodegit init
  3. add.gitignore
  4. node -v> .nvmrc
  5. npm init -y
  1. npm i -S next react react-dom
  2. add a script to your package.json like this:
    {"scripts": {"dev":"next","build":"next build","start":"next start"  }}
  1. npm i -D typescript @types/react @types/react-dom @types/node
  2. createtsconfig.json
    {"compilerOptions": {"allowJs":true,"allowSyntheticDefaultImports":true,"alwaysStrict":true,"esModuleInterop":true,"isolatedModules":true,"jsx":"preserve","lib": ["dom","es2017"    ],"module":"esnext","moduleResolution":"node","noEmit":true,"typeRoots": ["./node_modules/@types"    ],"noFallthroughCasesInSwitch":true,"noUnusedLocals":true,"noUnusedParameters":true,"resolveJsonModule":true,"removeComments":false,"skipLibCheck":true,"strict":true,"target":"esnext","forceConsistentCasingInFileNames":true,"baseUrl":"./src"  },"exclude": ["node_modules","next.config.js"  ],"include": ["**/*.ts","**/*.tsx"  ]}
  1. createsrc/pages folder (orpages)
  2. createpages.tsx undersrc/pages/ (i.e.src/pages/index.tsx for/ route)
  1. npm i -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react eslint-import-resolver-typescriptnpm i -D eslint-config-airbnb eslint-plugin-jsx-a11y eslint-plugin-import eslint-plugin-react-hooksnpm i -D prettier eslint-config-prettier eslint-plugin-prettier
  2. create.eslintrc.js
    module.exports={parser:'@typescript-eslint/parser',// Specifies the ESLint parserextends:['plugin:react/recommended',// Uses the recommended rules from@eslint-plugin-react'plugin:@typescript-eslint/recommended',// Uses the recommended rules from@typescript-eslint/eslint-plugin'airbnb',//Uses airbnb recommended rules'prettier/@typescript-eslint',// Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier'plugin:prettier/recommended',// Enables eslint-plugin-prettier and displays prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.],parserOptions:{ecmaVersion:2018,// Allows for the parsing of modern ECMAScript featuressourceType:'module',// Allows for the use of importsecmaFeatures:{jsx:true,// Allows for the parsing of JSX},},env:{browser:true,node:true},rules:{// Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs// e.g. '@typescript-eslint/explicit-function-return-type': 'off','no-unused-vars':'off','@typescript-eslint/no-unused-vars':['error',{'vars':'all','args':'after-used','ignoreRestSiblings':false}],'react/jsx-filename-extension':[1,{'extensions':['.js','.jsx','.ts','.tsx']}],'react/jsx-first-prop-new-line':0,'@typescript-eslint/no-explicit-any':'off','@typescript-eslint/explicit-function-return-type':0,'@typescript-eslint/no-namespace':'off','jsx-a11y/anchor-is-valid':['error',{'components':['Link'],'specialLink':['hrefLeft','hrefRight'],'aspects':['invalidHref','preferButton']}],'react/prop-types':'off','import/extensions':[1,{'extensions':['.js','.jsx','.ts','.tsx']}],'import/no-extraneous-dependencies':['error',{'devDependencies':true}],'comma-dangle':['error',{'arrays':'always-multiline','objects':'always-multiline','imports':'always-multiline','exports':'always-multiline','functions':'never'}],"react-hooks/rules-of-hooks":"error",'react-hooks/exhaustive-deps':'off','no-bitwise':'off'},plugins:['@typescript-eslint/eslint-plugin','react-hooks',],settings:{'import/resolver':{node:{extensions:['.js','.jsx','.ts','.tsx'],},typescript:{},},react:{version:'detect',// Tells eslint-plugin-react to automatically detect the version of React to use},},};
  3. create.prettierrc.js
    module.exports={semi:true,trailingComma:'es5',singleQuote:true,printWidth:80,tabWidth:2,};
  1. npm i -D jest babel-jest
  2. add scripts inpackage.json
    "scripts": {"test":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage"},
  3. npm i -D enzyme enzyme-adapter-react-16 enzyme-to-jsonnpm i -D typescript @types/enzyme @types/enzyme-adapter-react-16 @types/jest
  4. createjest.config.js
    module.exports={moduleFileExtensions:['ts','tsx','js'],testRegex:'(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|js?|tsx?|ts?)$',globals:{NODE_ENV:'test',},snapshotSerializers:['enzyme-to-json/serializer'],transform:{'^.+\\.(j|t)sx?$':'babel-jest',},coveragePathIgnorePatterns:['/node_modules/','jest.setup.js','<rootDir>/configs/','jest.config.js','.json','.snap',],setupFiles:['<rootDir>/jest/jest.setup.js'],coverageReporters:['json','lcov','text','text-summary'],moduleNameMapper:{'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':'<rootDir>/__mocks__/mocks.js','\\.(css|less|scss)$':'<rootDir>/__mocks__/mocks.js',},moduleDirectories:['node_modules','src'],};
  5. createbabel.config.js
    module.exports={presets:['next/babel'],};
  6. createjest/jest.setup.js
    importEnzymefrom'enzyme';importAdapterfrom'enzyme-adapter-react-16';import{join}from'path';import{loadEnvConfig}from'next/dist/lib/load-env-config';// to load '.env' files in testloadEnvConfig(join(__dirname,'.../'));Enzyme.configure({adapter:newAdapter()});
  7. changeenv in.eslintrc.js
    env:{browser:true,node:true,jest:true},
  1. npm i -S @emotion/corenpm i -D @emotion/babel-preset-css-prop jest-emotion eslint-plugin-emotion
  2. changebabel.config.js
    module.exports={presets:[['next/babel',{'preset-env':{},'preset-react':{},},],'@emotion/babel-preset-css-prop',],};
  3. add rules and plugins to.eslintrc.js
    module.exports={// ...rules:{// ..."emotion/no-vanilla":"error","emotion/import-from-emotion":"error","emotion/styled-import":"error",},// ...plugins:['emotion',// ...],// ...}
  4. addjest/jest.setupAfterEnv.js
    import{matchers}from'jest-emotion';expect.extend(matchers);
  5. add serializers and setup files tojest/jest.config.js
    // ...snapshotSerializers:['enzyme-to-json/serializer','jest-emotion'],// ...setupFilesAfterEnv:['<rootDir>/jest.setupAfterEnv.js'],// ...

(deploy to /docs intead of using gh-pages branch; replace{folder} with the project name in github repo)

  1. add.env.production
NEXT_PUBLIC_LINK_PREFIX=/{folder}
  1. createLINK_PREFIX innext.config.js
    constLINK_PREFIX=process.env.NEXT_PUBLIC_LINK_PREFIX||'';module.exports=()=>({assetPrefix:LINK_PREFIX,});
  2. changeas prop innext/Link to addlinkPrefix, similar tosrc/features/link/Link.tsx in the example setup
  3. changescripts inpackage.json
    {"scripts": {"export":"NODE_ENV=production npm run build && next export -o docs && touch docs/.nojekyll"  }}

Optional:

Optional chaining

  1. npm i -D @babel/plugin-proposal-nullish-coalescing-operator @babel/plugin-proposal-optional-chaining
  2. add the plugins tobabel.config.js
    module.exports={presets:[// ...],plugins:['@babel/plugin-proposal-optional-chaining','@babel/plugin-proposal-nullish-coalescing-operator',],};

  1. npm i -S react-redux @reduxjs/toolkitnpm i -D @types/react-redux
  2. either usenext-redux-wrapper package (npm i -P next-redux-wrapper) or copy thewithRedux.tsx from the example setupsrc/utils/redux
  3. create custommakeStore function,_app.tsx page and other redux setup as examples innext-redux-wrapper repo shows
  1. copyconfigureStore.ts,DynamicStoreWrap.tsx from the example setupsrc/utils/redux, andobjectAssign.ts fromsrc/utils/common
  2. changesrc/_app.tsx similar to the example setup
  1. npm i -S next-pwa
  2. changenext.config.js
    constisProd=process.env.NODE_ENV==='production';constFOLDER=LINK_PREFIX&&LINK_PREFIX.substring(1);// tranfrom precache url for browsers that encode dynamic routes// i.e. "[id].js" => "%5Bid%5D.js"constencodeUriTransform=async(manifestEntries)=>{constmanifest=manifestEntries.map((entry)=>{entry.url=encodeURI(entry.url);returnentry;});return{ manifest,warnings:[]};};module.exports=()=>withManifest(withPWA({// ...// service workerpwa:{disable:!isProd,subdomainPrefix:LINK_PREFIX,dest:'public',navigationPreload:true,},// manifestmanifest:{/* eslint-disable @typescript-eslint/camelcase */output:'public',short_name:FOLDER,name:FOLDER,start_url:`${LINK_PREFIX}/`,background_color:THEME_COLOR,display:'standalone',scope:`${LINK_PREFIX}/`,dir:'ltr',// text direction: left to righttheme_color:THEME_COLOR,icons:[{src:`${LINK_PREFIX}${ICON_192_PATH}`,sizes:'192x192',type:'image/png',},{src:`${LINK_PREFIX}${ICON_512_PATH}`,sizes:'512x512',type:'image/png',},],},}));
  3. addpublic/icons folder and include corresponding icon files in the folder
  4. copyManifestHead.tsx from the example setupsrc/features/head
  5. importManifestHead in pages
  1. npm i -S typeorm reflect-metadata sql.js localforage next-transpile-modulesnpm i -D webpack babel-plugin-transform-typescript-metadata @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties
  2. add tocompilerOptions intsconfig.json
    {"compilerOptions": {"emitDecoratorMetadata":true,"experimentalDecorators":true,  }}
  3. add to theplugins inbabel.config.js
// ...  plugins:['babel-plugin-transform-typescript-metadata',['@babel/plugin-proposal-decorators',{legacy:true}],['@babel/plugin-proposal-class-properties',{loose:true}],// ...]// ...
  1. add to the top of_app.tsx or whatever the entry file
    import'reflect-metadata';importlocalforagefrom'localforage';// ...declare global{interfaceWindow{localforage?:LocalForage;}}// ...// ...inside the AppuseEffect(()=>{window.localforage=localforage;return()=>{window.localforage=undefined;};},[]);// ...
  2. add tonext.config.js
    // ...constwithTM=require('next-transpile-modules')(['typeorm/browser']);constwebpack=require('webpack');const{ dependencies}=require('./package-lock.json');// ...module.exports=()=>/* ... other wrappers, like withPWA()  add withTM wrap innermost */withTM({webpack:(config,{ isServer})=>{config.plugins.push(newwebpack.ProvidePlugin({'window.SQL':'sql.js/dist/sql-wasm.js',}));if(!isServer){config.node={fs:'empty',net:'empty',tls:'empty',};}returnconfig;}// ...other existing configsenv:{NEXT_PUBLIC_SQL_JS_VERSION:dependencies['sql.js'].version||'',}})// ...
  3. copyconnection.ts fromsrc/sql/connection in the example setup and modify thedefaultEntities

Notes:

  1. NextJs, next-pwa, workbox are still growing their api, so this project setup will be modified in the future for easier setup.
  2. There is a known error on the workbox:GoogleChrome/workbox#2178.
  3. Only direct children innext/head will be picked up at build time, so allnext/link wrapped elements must be inserted (useEffect) after thenext/head is loaded.

About

Example Github Page PWA with NextJs, Redux-toolkit and Sql.js

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors2

  •  
  •  

[8]ページ先頭

©2009-2025 Movatter.jp