├── LOG.md ├── src ├── scss │ ├── main.scss │ └── components │ │ └── _base.scss ├── ts │ ├── another-file.ts │ ├── detects.ts │ ├── main.ts │ ├── components │ │ └── some-code.ts │ └── detects.spec.ts ├── img │ └── crab.jpg ├── copy │ ├── favicon │ │ ├── favicon.ico │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── apple-touch-icon.png │ │ ├── mstile-150x150.png │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── browserconfig.xml │ │ ├── site.webmanifest │ │ └── safari-pinned-tab.svg │ └── index.html └── svg │ └── icecream.svg ├── .gitignore ├── .idea └── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── karma.conf.js ├── rollup.config.js ├── sass.js ├── package.json ├── tsconfig.json └── README.md /LOG.md: -------------------------------------------------------------------------------- 1 | #### Day 1 2 | -------------------------------------------------------------------------------- /src/scss/main.scss: -------------------------------------------------------------------------------- 1 | @import "components/base"; 2 | -------------------------------------------------------------------------------- /src/ts/another-file.ts: -------------------------------------------------------------------------------- 1 | console.log('another-file.ts loaded'); 2 | -------------------------------------------------------------------------------- /src/img/crab.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomRaaff/TS-project-template/HEAD/src/img/crab.jpg -------------------------------------------------------------------------------- /src/ts/detects.ts: -------------------------------------------------------------------------------- 1 | export function addOne(num: number): number { 2 | return num + 1; 3 | } 4 | -------------------------------------------------------------------------------- /src/copy/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomRaaff/TS-project-template/HEAD/src/copy/favicon/favicon.ico -------------------------------------------------------------------------------- /src/copy/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomRaaff/TS-project-template/HEAD/src/copy/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /src/copy/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomRaaff/TS-project-template/HEAD/src/copy/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /src/copy/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomRaaff/TS-project-template/HEAD/src/copy/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /src/copy/favicon/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomRaaff/TS-project-template/HEAD/src/copy/favicon/mstile-150x150.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | !.idea/codeStyles/* 3 | package-lock.json 4 | compiledjs/ 5 | dist/ 6 | node_modules/ 7 | TS-project-template.iml 8 | coverage/ 9 | -------------------------------------------------------------------------------- /src/copy/favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomRaaff/TS-project-template/HEAD/src/copy/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /src/copy/favicon/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomRaaff/TS-project-template/HEAD/src/copy/favicon/android-chrome-512x512.png -------------------------------------------------------------------------------- /src/ts/main.ts: -------------------------------------------------------------------------------- 1 | import addClick from './components/some-code'; 2 | 3 | (function () { 4 | console.log('main.ts loaded'); 5 | addClick(); 6 | }()) 7 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /src/ts/components/some-code.ts: -------------------------------------------------------------------------------- 1 | export default function addClick() { 2 | document.addEventListener('click', function (event: MouseEvent) { 3 | alert('You clicked me!'); 4 | }, false); 5 | console.log('some-code.ts is loaded'); 6 | } 7 | -------------------------------------------------------------------------------- /src/scss/components/_base.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * @section Base Styles 3 | */ 4 | 5 | body { 6 | font-size: 125%; 7 | margin: 0 auto; 8 | max-width: 42em; 9 | width: 88%; 10 | } 11 | 12 | input, 13 | textarea, 14 | select, 15 | button { 16 | font: inherit; 17 | } -------------------------------------------------------------------------------- /src/ts/detects.spec.ts: -------------------------------------------------------------------------------- 1 | import { addOne } from './detects'; 2 | 3 | describe('Detects.addOne', () => { 4 | it('should add one to its input value', () => { 5 | // arrange 6 | const expected = 3; 7 | // act 8 | const result = addOne(2); 9 | // assert 10 | expect(result).toBe(3); 11 | }); 12 | }) 13 | -------------------------------------------------------------------------------- /src/copy/favicon/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/copy/favicon/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /src/svg/icecream.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | icecream 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/copy/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Copy Me 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |

Copy Me

20 | 21 |

Anything you put in the copy directory gets copied as-is into the dist directory.

22 | 23 |

24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function (config) { 2 | config.set({ 3 | frameworks: ['jasmine', 'karma-typescript'], 4 | files: [ 5 | { pattern: 'src/**/*.ts' } 6 | ], 7 | preprocessors: { 8 | '**/*.ts': ['karma-typescript'] 9 | }, 10 | reporters: ['progress', 'karma-typescript', 'kjhtml'], 11 | htmlReporter: { 12 | outputDir: 'coverage/karma_html', // where to put the reports 13 | templatePath: null, // set if you moved jasmine_template.html 14 | focusOnFailures: true, // reports show failures on start 15 | namedFiles: false, // name files instead of creating sub-directories 16 | pageTitle: null, // page title for reports; browser info by default 17 | urlFriendlyName: false, // simply replaces spaces with _ for files/dirs 18 | reportName: 'report-summary-filename', // report summary filename; browser info by default 19 | 20 | // experimental 21 | preserveDescribeNesting: false, // folded suites stay folded 22 | foldAll: false, // reports start folded (only with preserveDescribeNesting) 23 | }, 24 | browsers: ['Chrome'], 25 | singleRun: false, 26 | client: { 27 | clearContext: false 28 | } 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | // Plugins 2 | import { terser } from 'rollup-plugin-terser'; 3 | import { nodeResolve } from '@rollup/plugin-node-resolve'; 4 | import pkg from './package.json'; 5 | 6 | 7 | // Configs 8 | var configs = { 9 | files: ['main.js', 'detects.js', 'another-file.js'], // package root files 10 | formats: ['es'], // ['iife', 'es', 'amd', 'cjs'], 11 | default: 'es', 12 | pathIn: 'compiledjs', 13 | pathOut: 'dist/js', 14 | minify: true, 15 | sourceMap: false 16 | }; 17 | 18 | // Banner 19 | var banner = `/*! ${pkg.name} v${pkg.version} | (c) ${new Date().getFullYear()} ${pkg.author.name} | ${pkg.license} License | ${pkg.repository.url} */`; 20 | 21 | var createOutput = function (filename, minify) { 22 | return configs.formats.map(function (format) { 23 | var output = { 24 | file: `${configs.pathOut}/${filename}${format === configs.default ? '' : `.${format}`}${minify ? '.min' : ''}.js`, 25 | format: format, 26 | banner: banner 27 | }; 28 | if (format === configs.default) { 29 | output.name = pkg.name; 30 | } 31 | if (minify) { 32 | output.plugins = [terser()]; 33 | } 34 | 35 | output.sourcemap = configs.sourceMap 36 | 37 | return output; 38 | }); 39 | }; 40 | 41 | /** 42 | * Create output formats 43 | * @param {String} filename The filename 44 | * @return {Array} The outputs array 45 | */ 46 | var createOutputs = function (filename) { 47 | 48 | // Create base outputs 49 | var outputs = createOutput(filename); 50 | 51 | // If not minifying, return outputs 52 | if (!configs.minify) return outputs; 53 | 54 | // Otherwise, ceate second set of outputs 55 | var outputsMin = createOutput(filename, configs.minify); 56 | 57 | // Merge and return the two arrays 58 | return outputs.concat(outputsMin); 59 | 60 | }; 61 | 62 | /** 63 | * Create export object 64 | * @return {Array} The export object 65 | */ 66 | var createExport = function (file) { 67 | return configs.files.map(function (file) { 68 | var filename = file.replace('.js', ''); 69 | return { 70 | input: `${configs.pathIn}/${file}`, 71 | output: createOutputs(filename), 72 | plugins: [nodeResolve()], 73 | }; 74 | }); 75 | }; 76 | 77 | export default createExport(); 78 | -------------------------------------------------------------------------------- /sass.js: -------------------------------------------------------------------------------- 1 | var sass = require('sass'); 2 | var fs = require('fs'); 3 | var pkg = require('./package.json'); 4 | 5 | 6 | // Configs 7 | var configs = { 8 | files: ['main.scss'], 9 | pathIn: 'src/scss', 10 | pathOut: 'dist/css', 11 | indentType: 'tab', 12 | indentWidth: 1, 13 | minify: true, 14 | sourceMap: false 15 | }; 16 | 17 | // Banner 18 | var banner = `/*! ${pkg.name} v${pkg.version} | (c) ${new Date().getFullYear()} ${pkg.author.name} | ${pkg.license} License | ${pkg.repository.url} */`; 19 | 20 | var getOptions = function (file, filename, minify) { 21 | return { 22 | file: `${configs.pathIn}/${file}`, 23 | outFile: `${configs.pathOut}/${filename}`, 24 | sourceMap: configs.sourceMap, 25 | sourceMapContents: configs.sourceMap, 26 | indentType: configs.indentType, 27 | indentWidth: configs.indentWidth, 28 | outputStyle: minify ? 'compressed' : 'expanded' 29 | }; 30 | }; 31 | 32 | var writeFile = function (pathOut, fileName, fileData, printBanner = true) { 33 | // Create the directory path 34 | fs.mkdir(pathOut, { recursive: true }, function (err) { 35 | // If there's an error, throw it 36 | if (err) throw err; 37 | 38 | // Write the file to the path 39 | fs.writeFile(`${pathOut}/${fileName}`, fileData, function (err) { 40 | if (err) throw err; 41 | 42 | var data = fs.readFileSync(`${pathOut}/${fileName}`); 43 | var fd = fs.openSync(`${pathOut}/${fileName}`, 'w+'); 44 | var insert = printBanner ? new Buffer.from(banner + '\n') : ''; 45 | fs.writeSync(fd, insert, 0, insert.length, 0); 46 | fs.writeSync(fd, data, 0, data.length, insert.length); 47 | fs.close(fd, function (err) { 48 | if (err) throw err; 49 | console.log(`Compiled ${pathOut}/${fileName}`); 50 | }) 51 | }) 52 | }) 53 | } 54 | 55 | var parseSass = function (file, minify) { 56 | var filename = `${file.slice(0, file.length - 5)}${minify ? '.min' : ''}.css`; 57 | sass.render(getOptions(file, filename, minify), function (err, result) { 58 | 59 | // If there's an error, throw it 60 | if (err) throw err; 61 | 62 | // Write the file 63 | writeFile(configs.pathOut, filename, result.css); 64 | 65 | if (configs.sourceMap && !configs.sourceMapEmbed) { 66 | // Write external sourcemap 67 | writeFile(configs.pathOut, filename + '.map', result.map, false); 68 | } 69 | }); 70 | }; 71 | 72 | configs.files.forEach(function (file) { 73 | parseSass(file); 74 | if (configs.minify) { 75 | parseSass(file, configs.minify); 76 | } 77 | }); 78 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TS-project-template", 3 | "version": "2.0.0", 4 | "description": "Simple recipes for building and compiling with the CLI.", 5 | "author": { 6 | "name": "Tom Raaff", 7 | "url": "https://github.com/TomRaaff" 8 | }, 9 | "license": "MIT", 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/TomRaaff/TS-project-template" 13 | }, 14 | "scripts": { 15 | "start": "npm-run-all -p watch server-start", 16 | "test": "node_modules/karma/bin/karma start", 17 | "clean": "recursive-delete 'dist' && recursive-delete 'compiledjs'", 18 | "ts": "tsc", 19 | "js": "rollup --config", 20 | "css": "node sass.js", 21 | "svg": "svgo -f src/svg dist/svg -r --disable=removeViewBox,removeTitle", 22 | "img": "imagemin src/img/* --out-dir=dist/img --plugin=pngquant --plugin=mozjpeg --plugin=pngcrush --plugin=zopfli", 23 | "copy": "recursive-copy 'src/copy' 'dist'", 24 | "build-dirty": "npm run ts && npm-run-all -p js css svg img copy", 25 | "build": "npm-run-all -s clean build-dirty", 26 | "watch-ts": "chokidar './src/**/*.ts' -c 'npm run ts'", 27 | "watch-css": "chokidar './src/**/*.scss' -c 'npm run css'", 28 | "watch-js": "chokidar './compiledjs/**/*.js' -c 'npm run js'", 29 | "watch-svg": "chokidar './src/**/*.svg' -c 'npm run svg'", 30 | "watch-img": "chokidar './src/img/**/*.*' -c 'npm run img'", 31 | "watch-copy": "chokidar './src/copy/**/*.*' -c 'npm run copy'", 32 | "watch": "npm-run-all -p build watch-ts watch-css watch-js watch-svg watch-img watch-copy", 33 | "server-start": "browser-sync start --files 'dist' --server 'dist'" 34 | }, 35 | "devDependencies": { 36 | "@rollup/plugin-node-resolve": "^13.0.0", 37 | "@types/jasmine": "^3.7.8", 38 | "browser-sync": "^2.26.14", 39 | "chokidar-cli": "^2.1.0", 40 | "imagemin-cli": "^6.0.0", 41 | "imagemin-mozjpeg": "^8.0.0", 42 | "imagemin-pngcrush": "^6.0.0", 43 | "imagemin-pngquant": "^8.0.0", 44 | "imagemin-zopfli": "^6.0.0", 45 | "jasmine-core": "^3.8.0", 46 | "karma": "^6.3.4", 47 | "karma-chrome-launcher": "^3.1.0", 48 | "karma-jasmine": "^4.0.1", 49 | "karma-jasmine-html-reporter": "^1.6.0", 50 | "karma-typescript": "^5.5.1", 51 | "npm-run-all": "^4.1.5", 52 | "recursive-fs": "^2.1.0", 53 | "rollup": "^2.6.1", 54 | "rollup-plugin-terser": "^7.0.2", 55 | "sass": "^1.26.5", 56 | "svgo": "^1.3.2", 57 | "typescript": "^4.3.5" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 25 | 26 | 27 | 29 | 30 | 31 | 48 | 49 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/copy/favicon/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.14, written by Peter Selinger 2001-2017 9 | 10 | 12 | 22 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "module": "ES2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ 8 | "moduleResolution": "Node", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 9 | "lib": ["dom", "ES2020"], /* Specify library files to be included in the compilation. */ 10 | // "allowJs": true, /* Allow javascript files to be compiled. */ 11 | // "checkJs": true, /* Report errors in .js files. */ 12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ 13 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | "outDir": "./compiledjs", /* Redirect output structure to the directory. */ 18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true, /* Enable all strict type-checking options. */ 29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | // "strictNullChecks": true, /* Enable strict null checks. */ 31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 43 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */ 44 | // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ 45 | 46 | /* Module Resolution Options */ 47 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 48 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 49 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 50 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 51 | // "typeRoots": [], /* List of folders to include type definitions from. */ 52 | // "types": [], /* Type declaration files to be included in compilation. */ 53 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 54 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 55 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 56 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 57 | 58 | /* Source Map Options */ 59 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 60 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 61 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 62 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 63 | 64 | /* Experimental Options */ 65 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 66 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 67 | 68 | /* Advanced Options */ 69 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 70 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TS Project Template 2 | A simple template for using NPM tasks to build and compile TypeScript, JavaScript, CSS, and image files. 3 | Based on [Chris Ferdinandi's Build Tool Boilerplate](https://github.com/cferdinandi/build-tool-boilerplate) 4 | More info on Chris' [build filosophies.](https://open.spotify.com/episode/3bfISkRGO11Srs8Ask7N1H?si=k89d4n7hSgGp-0EpYOeQQw&utm_source=copy-link&dl_branch=1&nd=1) 5 | 6 | **Install** 7 | 8 | - [Install Node.js.](http://nodejs.org/) 9 | 10 | **Quick Start** 11 | 12 | Each task has just one or two dependencies (*except for image optimization*), so I recommend deleting the ones you don't need before running `npm install`. Learn more in [the documentation](#documentation) below. 13 | 14 | 1. In bash/terminal/command line, `cd` into your project directory. 15 | 2. Run `npm install`. 16 | 3. Run `npm run build`. 17 | 4. Run `npm start` to start local development 18 | 19 | 20 | ## Documentation 21 | 22 | This is a template that you can use as a starting point for your projects. 23 | 24 | [Running Tasks](#running-tasks) · [JavaScript](#javascript) · [Sass => CSS](#sass--css) · [SVG Optimization](#svg-optimization) · [Image Optimization](#image-optimization) · [Copy Files](#copy-files) · [Clean](#clean) · [Complete Build](#complete-build) · [Watch for Changes](#watch-for-changes) · [Server](#server) 25 | 26 | 27 | ### Running Tasks 28 | 29 | The template uses the `npm run` command to run tasks. These work on macOS, Linux, and Windows systems. 30 | 31 | ```bash 32 | # Main Tasks 33 | npm start # run a localhost server that reloads when files change] 34 | npm run test # run tests 35 | npm run ts # compile ts 36 | npm run js # compile and minify 37 | npm run css # compile and minify Sass into CSS 38 | npm run svg # optimize SVGs with SVGO 39 | npm run img # optimize image files 40 | npm run copy # copy files from the src/copy directory as-is into /dist 41 | npm run clean # delete the /dist directory 42 | npm run build # run all tasks 43 | npm run watch # watch for changes and rebuild 44 | 45 | # Modular Tasks 46 | npm run watch-ts # watch for changes to the /ts directory 47 | npm run watch-js # watch for changes to the /js directory 48 | npm run watch-css # watch for changes to the /css directory 49 | npm run watch-svg # watch for changes to the /svg directory 50 | npm run watch-img # watch for changes to the /img directory 51 | npm run watch-copy # watch for changes to the /copy directory 52 | npm run build-dirty # run a new build without deleting the /dist directory 53 | npm run server-start # start a server without watching for changes 54 | ``` 55 | 56 | ### Local Development 57 | use `npm run start` to build the project and start a server that reloads when file changes are detected. 58 | 59 | ### TypeScript 60 | Before any minification and bundling is done, all .ts files are first compiled and moved to the ./compiledjs folder. 61 | 62 | TypeScript files should be in the `src/ts` directory. 63 | 64 | ### JavaScript 65 | 66 | The template uses [rollup.js](https://rollupjs.org) with the [terser](https://terser.org/) plugin to parse, compile, and minify JavaScript files. 67 | 68 | ```json 69 | { 70 | "devDependencies": { 71 | "rollup": "^2.6.1", 72 | "rollup-plugin-terser": "^7.0.2" 73 | } 74 | } 75 | ``` 76 | 77 | In the `rollup.config.js` file, there's a `configs` object that you can use to control what rollup.js does. 78 | 79 | ```js 80 | // Configs 81 | var configs = { 82 | name: 'MyProject', // Global namespace to use for IIFEs [optional] 83 | files: ['main.js', 'detects.js'], // The files to process 84 | formats: ['iife', 'es'], // The formats to output - will be added as a suffix to the filename (ex. main.es.js) 85 | default: 'iife', // Files with this format will not have a format suffix [optional] 86 | pathIn: 'src/js', // The source directory for your JS files 87 | pathOut: 'dist/js', // The directory to compile JS files into 88 | minify: true, // If true, a minified version will also be created with the .min suffix 89 | sourceMap: false // If true, sourcemaps are created for each processed file † 90 | }; 91 | ``` 92 | 93 | A banner is automatically generated from your `package.json` data. 94 | 95 | It includes the project name and version, a copyright notice with the current year and the package author name, the license type, and a link to the project repository. 96 | 97 | _If a `configs.name` property is included, that will be used. If not, the banner defaults to the `name` property in your `package.json` file._ 98 | 99 | ```js 100 | // Banner 101 | var banner = `/*! ${configs.name ? configs.name : pkg.name} v${pkg.version} | (c) ${new Date().getFullYear()} ${pkg.author.name} | ${pkg.license} License | ${pkg.repository.url} */`; 102 | ``` 103 | 104 | To concatentate multiple files into one, use the ES modules `import` feature. 105 | 106 | ```js 107 | // myplugin.js 108 | // This will compile into /dist/js/myplugin.js, and will include helpers.js, app.js, and event-listeners.js 109 | 110 | import * as Helpers from './helpers.js'; 111 | import app from './app.js'; 112 | import './event-listeners.js'; 113 | ``` 114 | 115 | _**Note for FireFox users:** ensure that ['Use Source Maps'](https://github.com/cferdinandi/build-tool-boilerplate/issues/7#issuecomment-811432626), and ['Show original sources'](https://github.com/cferdinandi/build-tool-boilerplate/issues/7#issuecomment-811855711) options are enabled in Developer Tools._ 116 | 117 | ### Sass => CSS 118 | 119 | The template uses the Node implementation of [dart-sass](https://sass-lang.com/dart-sass) to parse `.scss` files into CSS. 120 | 121 | ```json 122 | { 123 | "devDependencies": { 124 | "sass": "^1.26.5" 125 | } 126 | } 127 | ``` 128 | 129 | In the `sass.js` file, there's a `configs` object that you can use to control what `dart-sass` does. 130 | 131 | ```js 132 | // Configs 133 | var configs = { 134 | name: 'MyProject', // The name to use in the file banner 135 | files: ['main.scss'], // The files to process 136 | pathIn: 'src/scss', // The source directory for your Sass files 137 | pathOut: 'dist/css', // The directory to compile CSS files into 138 | indentType: 'tab', // The type of indenting to use ['tab'|'spaces'] 139 | indentWidth: 1, // How many tabs or spaces to indent 140 | minify: true, // If true, a minified version will also be created with the .min suffix 141 | sourceMap: false, // If true, sourcemaps are created for each processed file † 142 | }; 143 | ``` 144 | 145 | A banner is automatically generated from your `package.json` data. 146 | 147 | It includes the project name and version, a copyright notice with the current year and the package author name, the license type, and a link to the project repository. 148 | 149 | _If a `configs.name` property is included, that will be used. If not, the banner defaults to the `name` property in your `package.json` file._ 150 | 151 | ```js 152 | // Banner 153 | var banner = `/*! ${configs.name ? configs.name : pkg.name} v${pkg.version} | (c) ${new Date().getFullYear()} ${pkg.author.name} | ${pkg.license} License | ${pkg.repository.url} */`; 154 | ``` 155 | 156 | Sass files should be in the `src/scss` directory. Use this task to run the build. 157 | 158 | ```bash 159 | npm run css 160 | ``` 161 | 162 | _**Note for FireFox users:** ensure that ['Use Source Maps'](https://github.com/cferdinandi/build-tool-boilerplate/issues/7#issuecomment-811432626), and ['Show original sources'](https://github.com/cferdinandi/build-tool-boilerplate/issues/7#issuecomment-811855711) options are enabled in Developer Tools._ 163 | 164 | ### SVG Optimization 165 | 166 | The template uses [svgo](https://github.com/svg/svgo) to remove the cruft that gets added to SVG files by many editors. 167 | 168 | ```json 169 | { 170 | "devDependencies": { 171 | "svgo": "^1.3.2" 172 | } 173 | } 174 | ``` 175 | 176 | For accessibility reasons, the boilerplate disables the settings that remove the `title` element and `viewBox` attribute. 177 | 178 | You can make additional command line configurations under the `svg` tasks in the `scripts` property of the `package.json` file. 179 | 180 | ```bash 181 | svgo -f src/svg dist/svg -r --disable=removeViewBox,removeTitle 182 | ``` 183 | 184 | SVGs should be in the `src/svg` directory. Use this task to run the build. 185 | 186 | ```bash 187 | npm run svg 188 | ``` 189 | 190 | 191 | ### Image Optimization 192 | 193 | The template uses [imagemin](https://www.npmjs.com/package/imagemin), with the [MozJPEG](https://github.com/imagemin/imagemin-mozjpeg), [pngcrush](https://github.com/imagemin/imagemin-pngcrush), [pngquant](https://github.com/imagemin/imagemin-pngquant), and [zopfli](https://github.com/imagemin/imagemin-zopfli) plugins. 194 | 195 | (*Yea, that's kind of lot, isn't it?*) 196 | 197 | ```json 198 | { 199 | "devDependencies": { 200 | "imagemin-cli": "^6.0.0", 201 | "imagemin-mozjpeg": "^8.0.0", 202 | "imagemin-pngcrush": "^6.0.0", 203 | "imagemin-pngquant": "^8.0.0", 204 | "imagemin-zopfli": "^6.0.0" 205 | } 206 | } 207 | ``` 208 | 209 | Image files should be in the `src/img` directory. Use this task to run the build. 210 | 211 | ```bash 212 | npm run img 213 | ``` 214 | 215 | ### Copy Files 216 | 217 | The template uses [recursive-fs](https://github.com/simov/recursive-fs) to provide a cross-OS copying solution. This package is also used for the `clean` task, so only remove it if you're deleting both tasks. 218 | 219 | ```json 220 | { 221 | "devDependencies": { 222 | "recursive-fs": "^2.1.0" 223 | } 224 | } 225 | ``` 226 | 227 | If you have files you want copied as-is, place them in the `src/copy` directory. 228 | 229 | Use this task to run the build. 230 | 231 | ```bash 232 | npm run copy 233 | ``` 234 | 235 | ### Clean 236 | 237 | The template uses [recursive-fs](https://www.npmjs.com/package/recursive-fs) to provide a cross-OS recursive directory deleting solution. This package is also used for the `copy` task, so only remove it if you're deleting both tasks. 238 | 239 | ```json 240 | { 241 | "devDependencies": { 242 | "recursive-fs": "^2.1.0" 243 | } 244 | } 245 | ``` 246 | 247 | You can delete the `/dist` directory before running a build to clean up any junk that might have ended up there. The `build` task runs this task before doing anything else. 248 | 249 | ```bash 250 | npm run clean 251 | ``` 252 | 253 | 254 | ### Complete Build 255 | 256 | You can run all of your build tasks in a single command. 257 | 258 | Use this task to run the build. 259 | 260 | ```bash 261 | npm run build 262 | ``` 263 | 264 | If you want to run your build _without_ first deleting the `/dist` directory, run this task instead. 265 | 266 | ```bash 267 | npm run build-dirty 268 | ``` 269 | 270 | Regardless of which task you use, be sure to delete any tasks you're not using from the `build-dirty` task under `scripts` in your `package.json` file first. The `npm-run-all -p` command is used to run all tasks in parallel ([see below for more details](#core-dependencies)). 271 | 272 | ```bash 273 | # default build-dirty task 274 | npm-run-all -p js css svg img copy 275 | ``` 276 | 277 | #### What 'build' DOES NOT do: 278 | - uglify all JS 279 | - bundle all JS into a single file. 280 | Instead, it bundles based on the input files you assign in the rollup config. So it is more modular. 281 | 282 | ### Watch for Changes 283 | 284 | The template uses [Chokidar CLI](https://www.npmjs.com/package/chokidar-cli) to watch for changes to the `/src` directory and run tasks in response. 285 | 286 | ```json 287 | { 288 | "devDependencies": { 289 | "chokidar-cli": "^2.1.0" 290 | } 291 | } 292 | ``` 293 | 294 | Use this task to watch for changes and run a build. It will also run a fresh build when it starts. 295 | 296 | ```bash 297 | npm run watch 298 | ``` 299 | 300 | If you only want to watch for changes to a specific directory in `/src`, you can use a task-specific watcher task. 301 | 302 | ```bash 303 | npm run watch-js # watch for changes to the /js directory 304 | npm run watch-css # watch for changes to the /css directory 305 | npm run watch-svg # watch for changes to the /svg directory 306 | npm run watch-img # watch for changes to the /img directory 307 | npm run watch-copy # watch for changes to the /copy directory 308 | ``` 309 | 310 | 311 | ## Server 312 | 313 | The template uses [Browsersync](https://www.browsersync.io/) to run a local server and automatically update it whenever your files change. 314 | 315 | ```json 316 | { 317 | "devDependencies": { 318 | "browser-sync": "^2.26.14" 319 | } 320 | } 321 | ``` 322 | 323 | Use this task to watch for changes. It will also run the `watch` task, and automatically rebuild whenever a file in `/src` changes. 324 | 325 | ```bash 326 | npm run server 327 | ``` 328 | 329 | If you want to run the server _without_ the `watch` task, run this task instead. 330 | 331 | ```bash 332 | npm run server-start 333 | ``` 334 | 335 | 336 | 337 | ## Core Dependencies 338 | 339 | The template uses [npm-run-all](https://www.npmjs.com/package/npm-run-all) to run tasks consistently across different operating systems, and in parallel. 340 | 341 | ```json 342 | { 343 | "devDependencies": { 344 | "npm-run-all": "^4.1.5" 345 | } 346 | } 347 | ``` 348 | 349 | The `npm-run-all` package removes the need for Windows-specific tasks. 350 | 351 | It also allows you to run tasks in parallel. By running all of the tasks in the `build` tasks at the same time, you dramatically reduce the build time. This is also what makes it possible to run a localhost server _and_ watch for file changes in one task. 352 | 353 | **In other words, don't remove this dependency.** 354 | 355 | 356 | 357 | ## Why does this exist? 358 | 359 | I have been working with Webpack until now and I was never quite pleased with the way webpack worked. 360 | Too much magic for my taste. I wanted something simple and lean. I found Chris Ferdinandi's Boilerplate project and it 361 | was exactly what I was looking for. I added TypeScript and a test-framework. 362 | --------------------------------------------------------------------------------